目标
给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lower 和 upper ,返回 公平数对的数目 。
如果 (i, j) 数对满足以下情况,则认为它是一个 公平数对 :
- 0 <= i < j < n,且
- lower <= nums[i] + nums[j] <= upper
示例 1:
输入:nums = [0,1,7,4,4,5], lower = 3, upper = 6
输出:6
解释:共计 6 个公平数对:(0,3)、(0,4)、(0,5)、(1,3)、(1,4) 和 (1,5) 。
示例 2:
输入:nums = [1,7,9,2,5], lower = 11, upper = 11
输出:1
解释:只有单个公平数对:(2,3) 。
说明:
- 1 <= nums.length <= 10^5
- nums.length == n
- -10^9 <= nums[i] <= 10^9
- -10^9 <= lower <= upper <= 10^9
思路
计算数组中公平数对的个数,定义公平数对 (i, j)
满足 0 <= i < j < n && lower <= nums[i] + nums[j] <= upper
。
对于下标 i
,与之匹配的下标 j
需满足 j > i && lower - nums[i] <= nums[j] <= upper - nums[i]
。公平数对下标不能相同,只要没有重复组合 i < j
或者 j < i
都可以,不关心相对位置,可以排序。
针对每一个下标 i
在 [i + 1, n - 1]
内二分查找上下界,计算其中的元素个数即可。
代码
/**
* @date 2025-04-19 21:41
*/
public class CountFairPairs2563 {
public long countFairPairs(int[] nums, int lower, int upper) {
long res = 0L;
Arrays.sort(nums);
int n = nums.length;
for (int i = 0; i < n; i++) {
int l = lowerBound(i + 1, n - 1, lower - nums[i], nums);
int r = upperBound(i + 1, n - 1, upper - nums[i], nums);
res += r - l + 1;
}
return res;
}
public int lowerBound(int left, int right, int target, int[] nums) {
int mid = left + (right - left) / 2;
while (left <= right) {
if (target <= nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
mid = left + (right - left) / 2;
}
return left;
}
public int upperBound(int left, int right, int target, int[] nums) {
int mid = left + (right - left) / 2;
while (left <= right) {
if (target >= nums[mid]) {
left = mid + 1;
} else {
right = mid - 1;
}
mid = left + (right - left) / 2;
}
return right;
}
}