910. 最小差值 II
题目来源:力扣(LeetCode)
https://leetcode-cn.com/problems/smallest-range-ii/
解题思路:
这道题的题意是A数组中的每个元素要么加K、要么减K,只能进行其中的一个操作。在每个元素操作完后就构成一个新的数组B,要求使B中数组元素的最大值与最小值的差值最小。
对于这道题,我们先来考虑所有情况:假设两个数x、y,且x<y。
1、x、y都加K与都减K的结果与原数组A中的最大最小元素的差值一样。算一种情况。 即 (y+k)-(x+k)=y-k 或 (y-k)-(x-k)=y-k 。
2、y加k、x减k。即(y+k)-(x-k)=y-x+2k。
3、y减k、x加k。即(y-k)-(x+k)=y-x-2k。
若k>0,我们只需要考虑第三种情况。只有第三种情况下的值最小(可能与第一种一样)。
那么我们可以想,先将原数组进行从小到大排序,这样得到原数组中最小元素A[0]与最大元素A[n-1]。此时最大与最小元素差值为A[n-1]-A[0]。此时包括第一种情况。
对于第二种情况,当大的元素加K而小的元素减K,最终会导致新数组元数中的最大值与最小值之差比原数组的结果大,故不需要考虑。
最终只有第三种情况需要考虑,即大的元素减K,小的元素加K,这种情况才可能出现比原数组的结果更小的结果。注意:差值最大不会大于A[n-1]-A[0],只能比A[n-1]-A[0]小。
现在如何根据第三种情况使结果最小。首先根据排序后的数组,我们得到第一种情况的解;现在再遍历排序后的数组的相邻两位数,如A[i]、A[i+1],有A[i]<A[i+1]。A[i]+k一定会大于A[0]+k,只需要考虑A[i]+k与A[n-1]-k的大小,要在这两者中选一个最大的;A[i+1]-k一定小于A[n-1]-k,只需要考虑A[i+1]-k与A[0]+k的大小,要在这两者中选一个最小的。这样就得到一个新数组中的结果。
代码:
public int smallestRangeII(int[] A, int K) {
// 先对数组进行排序
Arrays.sort(A);
int n = A.length; // 数组长度
// 排序后,A[0]为数组最小值,A[n-1]为数组最大值。求得原数组中最大与最小值之差
int res = A[n-1]-A[0];
// 遍历数组中的每相邻的两个元素
for (int i = 0; i < n-1; i++) {
int max = Math.max(A[n-1]-K,A[i]+K);
int min = Math.min(A[0]+K,A[i+1]-K);
int error = max - min;
// 取小的结果。
res = Math.min(res,error);
}
return res;
}