题目

给你一个整数数组 nums,和一个整数 k 。

对于每个下标 i(0 <= i < nums.length),将 nums[i] 变成 nums[i] + k 或 nums[i] - k 。

nums 的 分数 是 nums 中最大元素和最小元素的差值。

在更改每个下标对应的值之后,返回 nums 的最小 分数 。

示例 1:

输入:nums = [1], k = 0
输出:0
解释:分数 = max(nums) - min(nums) = 1 - 1 = 0 。

示例 2:

输入:nums = [0,10], k = 2
输出:6
解释:将数组变为 [2, 8] 。分数 = max(nums) - min(nums) = 8 - 2 = 6 。

示例 3:

输入:nums = [1,3,6], k = 3
输出:3
解释:将数组变为 [4, 6, 3] 。分数 = max(nums) - min(nums) = 6 - 3 = 3 。

提示:

1 <= nums.length <= 10^4
0 <= nums[i] <= 10^4
0 <= k <= 10^4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-range-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

将数组排序,对于较小的值我们希望其加上k变大,对于较大的值我们希望其减去k变小,这样可以缩小两个最值的差距。

而且,对于某一下标i,如果nums[i]增加k,nums[i+1]减去k,那么i左侧的一定都是加k,i+1右侧的一定是减k。这一点比较好理解也可以证明。

如果出现上面的情况,那么就会出现当nums[i]<nums[j], i<j, 有将nums[i]减k,将nums[j]加k的情况,将较小的值变得更小,较大的值变得更大,这是没有意义的,获得的结果肯定不会优于将小值增大,将大值减小。

因此,可以枚举下标i,在此之前(包括i)所有数都加k,之后的减k。

代码

  1. class Solution {
  2. public int smallestRangeII(int[] nums, int k) {
  3. Arrays.sort(nums);
  4. int n = nums.length;
  5. int minNum = 0;
  6. int maxNum = 0;
  7. int ans = nums[n - 1] - nums[0];
  8. // i下标是最后一个加k的,即从i+1开始的数都减k
  9. for (int i = 0; i < n - 1; i++) {
  10. maxNum = Math.max(nums[i] + k, nums[n - 1] - k);
  11. minNum = Math.min(nums[0] + k, nums[i + 1] - k);
  12. ans = Math.min(ans, maxNum - minNum);
  13. }
  14. return ans;
  15. }
  16. }