目标
给你一个整数数组 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
思路
这道题与 908.最小差值I 的区别是对于每个元素操作是 必选的,增加或减少的值 固定 为 k
而不是区间 [-k, k]
。
每个元素都可以取 nums[i] + k
或 nums[i] - k
,如果枚举所有可能的数组,然后再取最大最小值差的最小值显然是不可能的。不考虑重复元素的情况下,可能的数组有 2^n
种。
可以先排序,增大小的值,减少大的值,枚举二者的边界,比如前 i
个元素 [0, i - 1]
加 k
,剩余元素减 k
,这时上界为 Math.max(nums[i - 1] + k, nums[n - 1] - k)
,下界为 Math.min(nums[0] + k, nums[i] - k)
,取上下界的最小值即可。
代码
/**
* @date 2024-10-21 9:57
*/
public class SmallestRangeII910 {
public int smallestRangeII(int[] nums, int k) {
Arrays.sort(nums);
int n = nums.length;
int res = nums[n - 1] - nums[0];
for (int i = 1; i < n; i++) {
int max = Math.max(nums[i - 1] + k, nums[n - 1] - k);
int min = Math.min(nums[0] + k, nums[i] - k);
res = Math.min(res, max - min);
}
return res;
}
}