Problem of The Day: Count the number of fair pairs
Problem Statement
Intuition
To solve this problem efficiently, we want to avoid checking all pairs directly, which would result in O(n²) time. Instead, we consider sorting the array and using a two-pointer technique to count the number of valid pairs within the given sum range. This approach is both elegant and efficient.
Approach
- Sort the input array
numsto enable efficient range-based sum counting using the two-pointer technique. - Define a helper function
helper(target)that counts the number of index pairs(i, j)wherenums[i] + nums[j] < target.- Use two pointers
landrto scan the array from both ends. - If the sum of
nums[l] + nums[r]is less thantarget, all elements betweenlandrcan form a valid pair withnums[l]. Increment the count accordingly and movelforward. - Otherwise, move
rbackward to find a smaller pair.
- Use two pointers
- Use the helper function to calculate:
helper(upper + 1)→ counts pairs with sum ≤upperhelper(lower)→ counts pairs with sum <lower- The result is the difference:
helper(upper + 1) - helper(lower), which gives the number of pairs with sum in[lower, upper].
Complexity
-
Time complexity:
\(O(n \log n)\)
Sorting takes ( O(n \log n) ) and each helper call takes ( O(n) ). Since we call the helper twice, total time is still ( O(n \log n) ). -
Space complexity:
\(O(1)\)
Aside from sorting (which may require some space depending on the implementation), no extra space is used.
Code
class Solution:
def countFairPairs(self, nums: List[int], lower: int, upper: int) -> int:
N = len(nums)
nums.sort()
def helper(target):
l, r = 0, N - 1
ans = 0
while l < r:
val = nums[l] + nums[r]
if val < target:
ans += r - l
l += 1
else:
r -= 1
return ans
return helper(upper + 1) - helper(lower)