最小差值II

2024-10-21

题目:

给你一个整数数组 nums,和一个整数 k 。对于每个下标 i0 <= i < nums.length),将 nums[i] 变成 nums[i] + knums[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 <= 104
  • 0 <= nums[i] <= 104
  • 0 <= k <= 104

思路:

由于每个值都要进行操作,所以利用贪心处理

排序 + 贪心枚举分界点。每个数位必须操作一次,贪心思路是让大值变小、小值变大,即排序后以某个点i为分界线,i及其左侧全+k,i右侧全-k,枚举i记录最小极差即可。

代码:

class Solution {
public:
    int smallestRangeII(vector<int>& nums, int k) {
        // 排序 + 贪心枚举
        sort(nums.begin(), nums.end());
        // diff初值为nums全+k或全-k的极差,后续枚举分界点i。
        int n = nums.size(), diff = nums[n - 1] - nums[0];
        // 枚举分界点,i及左侧均 + k,右侧i + 1开始均-k,
        // 那么max取左半段最大值(nums[i] + k)与右半段最大值(nums[n-1] - k)中较大者,
        // min取左半段最小值(nums[0] + k)与右半段最小值(nums[i+1] - k)中较小者。
        for (int i = 0; i < n - 1; i++) {
            int R = max(nums[i] + k, nums[n - 1] - k);
            int L = min(nums[0] + k, nums[i + 1] - k);
            diff = min(diff, R - L);
        }
        return diff;
    }
};