leetcode_910 最小差值 II

182 阅读2分钟

要求

给你一个整数数组 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 <= 10410^4
  • 0 <= nums[i] <= 10410^4
  • 0 <= k <= 10410^4

核心代码

class Solution:
    def smallestRangeII(self, nums: List[int], k: int) -> int:
        nums.sort()
        min_num,max_num = nums[0],nums[-1]
        ans = max_num - min_num
        for divide_left,divide_right in zip(nums[:-1],nums[1:]):
            ans = min(ans,max(max_num - k,divide_left + k) - min(min_num + k ,divide_right - k))
        return ans

image.png

解题思路:这道题的意思是,给出一个数组,让我们对其中的所有元素进行+K或-K操作,这些操作都是我们自己选择的,目的是让操作完成后整个数组的最大值与最小值之间的差距最小。

我们把数组从小到大排序,为了削弱最大值与最小值之间的差距,理所应当的,我们需要把较大的那几个数字-K,剩下的较小的数字统统+K,问题就在于,如何去划分这两批数字

一次前向遍历就可以实现。假设最左端和最右端的数字分别是min_num和max_num划分点处左侧和右侧的数字分别是divide_left,divide_right,因为排序的缘故,divide_left不大于divide_right,divide_left及其左半边的数字划分成一类,对这些数字进行+K操作,divide_right及其右半边的数字划分成一类,对这些数字进行-K操作。

如果我们画一条以下标为横轴,以数值为纵轴的线,这样一来,在划分点处就会出现断崖,但是分成的两段又各自是递增的。接下来就是如何求这种情况下的最大值与最小值的差值的问题。很显然,最大值一定在两个线段的右端点divide_left+K和max_num-K中产生,我们取其中最大值即可,最小值一定在两个线段的左端点min_num+K和divide_right-K中产生,我们取其中的最小值即可。这样一来,最大值与最小值一减,就获得了当前划分方式下的最大最小值之差。

我们统计一下每种划分方式下的最大最小值之差,选取其中的最小值即为题目所求。