LeetCode 2563. 统计公平数对的数目

本文介绍了一种使用二分查找解决公平数对问题的方法,给定一个整数数组nums和两个整数lower和upper,目标是找出满足条件0<i<j<n且lower<=nums[i]+nums[j]<=upper的数对数量。文章详细展示了如何通过排序数组并运用二分查找来优化时间复杂度至O(nlogn)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个下标从 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,9) 。

解法:二分

class Solution {
    public long countFairPairs(int[] nums, int lower, int upper) {
        Arrays.sort(nums);
        // nums[i] 范围:[lower - nums[j] , upper - nums[j]]
        // 枚举i,找到满足(nums[j] <= upper - nums[i] 的j的个数) - (nums[j] < lower - nums[i] 的j的个数)
        long ans = 0;
        // 0 <= i < j < n 即 0 <= i < n - 1, i < j < n
        for (int i = 0; i < nums.length - 1; i++) {
            // i < j,枚举i,找满足要求的j的个数,二分查找i + 1为左边界
            // nums[lowerBound] >= lower - nums[i]
            int lowerBound = getLowerBound(nums, i, lower); 
            // nums[upperBound] <= upper - nums[i]
            int upperBound = getUpperBound(nums, i, upper);
            ans += upperBound - lowerBound + 1;
        }
        return ans;
    }

    private int getUpperBound(int[] nums, int i, int goal) {
        int left = i + 1;
        int right = nums.length - 1;
        while (left <= right) {
            // 循环不变量:
            // nums[right + 1] > goal - nums[i]
            // nums[left - 1] <= goal - nums[i]
            int mid = left + (right - left) / 2;
            if (nums[mid] > goal - nums[i]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return right;
    }

    private int getLowerBound(int[] nums, int i, int goal) {
        int left = i + 1;
        int right = nums.length - 1;
        while (left <= right) {
            // 循环不变量:
            // nums[right + 1] >= goal - nums[i]
            // nums[left - 1] < goal - nums[i]
            int mid = left + (right - left) / 2;
            if (nums[mid] < goal - nums[i]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return left;
    }
}

复杂度分析

  • 时间复杂度:O(nlog⁡n),其中 n 为 nums 的长度。
  • 空间复杂度:O(1)。忽略排序的栈开销,仅用到若干额外变量。

相似题型:

LeetCode 930. 和相同的二元子数组-优快云博客

LeetCode 1248. 统计「优美子数组」-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值