在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,不是在区间内任选。这道题不能只看原始最大最小值,需要排序+遍历。

总结

这道题是简单的贪心题,难点不在于编码,而在于跳出“每个数字都可变所以情况很多”的思维陷阱,找到真正约束答案的瓶颈。以后遇到这类区间调整求极差最小的题目,可以先思考:谁是边界瓶颈。

posted @ 2026-10-22 17:41  绝望蘑菇头  阅读(3)  评论(0)    收藏  举报