2563.统计公平数对的数目

目标

给你一个下标从 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;
    }

}

性能

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注