在LeetCode做简单数组题的第3天
前言
LeetCode 908. 最小差值 I|贪心思路复盘
题目描述
给你一个整数数组 nums,和一个整数 k 。
在一个操作中,您可以选择 0 <= i < nums.length 的任何索引 i 。将 nums[i] 改为 nums[i] + x ,其中 x 是一个范围为 [-k, k] 的任意整数。对于每个索引 i ,最多只能应用一次此操作。
nums 的分数是 nums 中最大和最小元素的差值。
在对 nums 中的每个索引最多应用一次上述操作后,返回 nums 的最低分数。
简单理解:每个数字可以在
[nums[i]-k, nums[i]+k]区间内任选一个值,求调整之后数组极差(最大值-最小值)的最小值。
蘑菇的思考过程(迷惑记录)
一开始我被“每个数字都可以变化”迷惑,一直在想怎么枚举所有组合,寻找调整后的最大最小值。
后来慢慢梳理出一个猜想:
原数组最小值尽量往大拉:min + k
原数组最大值尽量往小拉:max - k
如果 max - k <= min + k,说明两个区间可以重叠,所有数字都能调整到同一个值,分数就是0;否则最小分数就是两者之差。
这个思路想出来之后,我自己不敢相信答案居然只需要原始数组的最大、最小值,中间元素完全不用考虑。(然后看到本题的筛选标签是 简单 。)
核心——贪心
所有中间元素的可选区间,天然落在 [min−k, max+k] 之间,不会成为新的上下界瓶颈。
限制最终极差的只有原始全局最小值和全局最大值:
- 最小值能向右移动的最远位置:
minV + k - 最大值能向左移动的最远位置:
maxV - k
如果这两个位置能碰上或者交叉,极差可以压缩到 0;否则它们之间的距离就是理论上最小的极差。
初次编码遇到的 Bug
def smallestRangeI(nums, k):
min = min(nums)
max = max(nums)
return max(0, (maxV - k) - (minV + k))
报错:UnboundLocalError: cannot access local variable 'max' where it is not associated with a value
错误:使用
min、max作为变量名,覆盖 Python 内置函数,属于坏习惯,这是习惯用LLM写代码后犯的第二个低级错误。
正确代码
def smallestRangeI(nums, k):
minV = min(nums)
maxV = max(nums)
return max(0, (maxV - k) - (minV + k))
代码解释
minV = min(nums):拿到原始数组最小值maxV = max(nums):拿到原始数组最大值(maxV - k) - (minV + k):最大值左移、最小值右移之后的间距max(0, ...):防止间距为负数(区间重叠时,直接返回0)
测试样例
print(smallestRangeI([1,3,6], 2)) # 输出 1
print(smallestRangeI([0,10], 2)) # 输出 6
print(smallestRangeI([4,6], 1)) # 输出 0
易混题提醒(姊妹题)
LeetCode 910 最小差值 II:每个数字必须选择 +k 或者 -k,不是在区间内任选。这道题不能只看原始最大最小值,需要排序+遍历。
总结
这道题是简单的贪心题,难点不在于编码,而在于跳出“每个数字都可变所以情况很多”的思维陷阱,找到真正约束答案的瓶颈。以后遇到这类区间调整求极差最小的题目,可以先思考:谁是边界瓶颈。
浙公网安备 33010602011771号