Count the Number of Fair Pairs — LeetCode #2563 (Medium)
Tags: Array, Two Pointers, Binary Search, Sorting
Related patterns: Two Pointers, Binary Search, Sorting
Brute Force approach
Time complexity: O(n²). Space complexity: O(1).
The brute force approach checks every possible pair of indices in the array to see if they meet the fair pair criteria. This is straightforward but inefficient, especially for large arrays.
This complexity arises because we are checking every possible pair of elements in the array, leading to n(n-1)/2 comparisons in the worst case.
- Step 1: Initialize a counter to zero for counting fair pairs.
- Step 2: Use two nested loops to iterate through all pairs (i, j) where i < j.
- Step 3: For each pair, check if the sum of nums[i] + nums[j] is within the range [lower, upper]. If it is, increment the counter.
- Step 4: Return the counter as the result.
Let's dry run the first example with nums = [0,1,7,4,4,5], lower = 3, upper = 6:
1. i=0, j=1: 0+1=1 (not fair)
2. i=0, j=2: 0+7=7 (not fair)
3. i=0, j=3: 0+4=4 (fair)
4. i=0, j=4: 0+4=4 (fair)
5. i=0, j=5: 0+5=5 (fair)
6. i=1, j=2: 1+7=8 (not fair)
7. i=1, j=3: 1+4=5 (fair)
8. i=1, j=4: 1+4=5 (fair)
9. i=1, j=5: 1+5=6 (fair)
10. i=2, j=3: 7+4=11 (not fair)
11. i=2, j=4: 7+4=11 (not fair)
12. i=2, j=5: 7+5=12 (not fair)
13. i=3, j=4: 4+4=8 (not fair)
14. i=3, j=5: 4+5=9 (not fair)
15. i=4, j=5: 4+5=9 (not fair)
Total fair pairs found: 6.
Optimal Solution approach
Time complexity: O(n log n). Space complexity: O(1).
By sorting the array and using a two-pointer technique, we can efficiently find the number of fair pairs without checking every possible combination. This reduces the time complexity significantly.
The sorting step takes O(n log n), and the two-pointer technique runs in O(n), making this approach much more efficient than the brute force method.
- Step 1: Sort the array nums.
- Step 2: Initialize a counter for fair pairs.
- Step 3: For each element nums[i], use binary search to find the range of indices that can form fair pairs with nums[i].
- Step 4: Count the valid pairs using the indices found in the previous step and update the counter.
- Step 5: Return the counter as the result.
Let's dry run the first example with nums = [0,1,7,4,4,5], lower = 3, upper = 6:
1. Sort nums: [0, 1, 4, 4, 5, 7]
2. For i=0 (nums[0]=0):
- left = binarySearch(3-0=3) -> index 2
- right = binarySearch(6-0=6) -> index 5
- count += 5 - 2 = 3
3. For i=1 (nums[1]=1):
- left = binarySearch(3-1=2) -> index 2
- right = binarySearch(6-1=5) -> index 5
- count += 5 - 2 = 3
4. For i=2 (nums[2]=4):
- left = binarySearch(3-4=-1) -> index 3
- right = binarySearch(6-4=2) -> index 3
- count += 3 - 3 = 0
5. For i=3 (nums[3]=4):
- left = binarySearch(3-4=-1) -> index 4
- right = binarySearch(6-4=2) -> index 4
- count += 4 - 4 = 0
6. For i=4 (nums[4]=5):
- left = binarySearch(3-5=-2) -> index 5
- right = binarySearch(6-5=1) -> index 5
- count += 5 - 5 = 0
Final count = 6.
Key Insights
- Sorting the array allows us to efficiently find pairs that meet the criteria using binary search.
- Using two pointers or binary search reduces the number of comparisons significantly.
Common Mistakes
- Not considering the constraints of indices (i < j) when counting pairs.
- Overlooking the importance of sorting the array before applying binary search.
Interview Tips
- Always explain your thought process clearly, especially when transitioning from brute force to optimal solutions.
- Practice identifying patterns in problems, such as when to use sorting or two-pointer techniques.
- Be mindful of edge cases, such as very small or very large values for lower and upper.