> 文章列表 > 最小化数对的最大差值

最小化数对的最大差值

最小化数对的最大差值

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