最小化数对的最大差值

给你一个下标从 0 开始的整数数组 nums 和一个整数 p 。请你从 nums 中找到 p 个下标对,每个下标对对应数值取差值,你需要使得这 p 个差值的 最大值 最小。同时,你需要确保每个下标在这 p 个下标对中最多出现一次。

对于一个下标对 i 和 j ,这一对的差值为 |nums[i] - nums[j]| ,其中 |x| 表示 x 的 绝对值

请你返回 p 个下标对对应数值 最大差值最小值

示例 1:

输入:nums = [10,1,2,7,1,3], p = 2
输出:1
解释:第一个下标对选择 1 和 4 ,第二个下标对选择 2 和 5 。
最大差值为 max(|nums[1] - nums[4]|, |nums[2] - nums[5]|) = max(0, 1) = 1 。所以我们返回 1 。

示例 2:

输入:nums = [4,2,1,2], p = 1
输出:0
解释:选择下标 1 和 3 构成下标对。差值为 |2 - 2| = 0 ,这是最大差值的最小值。

提示:

1 <= nums.length <= 10^5
0 <= nums[i] <= 10^9
0 <= p <= (nums.length)/2

解题思路:

二分法+贪心
二分数对中的最大差值 mx。

由于下标和答案无关,可以先排序。为了让差值最小,尽量选相邻的元素。

我们来算一算最多能匹配多少个数对:

如果可以选 nums[0] 和 nums[1],那么答案等于「n−2 个数的最多数对个数」+1。
如果不选 nums[0],那么答案等于「n−1个数的最多数对个数」,但这不会超过「n−3个数的最多数对个数」+1。这里 +1表示选 nums[1] 和 nums[2]。
由于「n−2个数的最多数对个数」≥「n−3 个数的最多数对个数」,所以如果可以选 nums[0] 和 nums[1],那么直接选就行。
依此类推,不断缩小问题规模。

通俗的来说:

将差值的范围不断缩小,以找到数组中p个最小差值的最大值,且要求每个元素只能取一次。第一层循环应该是差值的范围,计算中间值;第二层循环应该找到小于这个中间值的差值,当前差值满足这个条件,我们将直接跳过这一对数,所以i+2,计数器加一;判断下一对数,如果不满足,我们将求这个数对中右数与下一个数构成的差值。第二层循环结束后,我们看计数器是否满足大于等于p,满足我们则可将右指针左移,进一步往左缩小范围,否则往右缩小范围。一直这样直至找到满足题意的值。

class Solution {
    public int minimizeMax(int[] nums, int p) {
        Arrays.sort(nums);
        int left=-1,right=nums[nums.length-1]-nums[0];
        while(left+1<right){
            int mid=(left+right)/2,cnt=0;
            for(int i=0;i<nums.length-1;++i){
                if(nums[i+1]-nums[i]<=mid){
                    cnt++;
                    i+=1;
                }
            }   
            if(cnt>=p) right=mid;
            else left=mid;
        }
        return right;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Annimi@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值