发布时间:2026/8/25 3:29:24
力扣908题最小差值I:数学思维与极值调整的Python高效解法 在算法刷题的过程中我们常常会遇到一类看似简单实则暗藏数学巧思的题目。力扣LeetCode第908题「最小差值 I」就是其中的典型代表。很多同学初次看到题目描述时可能会觉得一头雾水或者尝试用复杂的排序、遍历去解决结果要么超时要么代码冗长。本文将为你彻底拆解这道题揭示其背后的数学本质并提供清晰、高效的Python解决方案。无论你是正在准备面试的求职者还是希望提升算法思维的学生掌握这道题的解法都能让你对“极值”和“范围”类问题有更深的理解。1. 问题背景与核心概念1.1 问题描述与官方链接力扣第908题「最小差值 I」的官方描述如下 给你一个整数数组nums和一个整数k。 对于数组中的每个下标i0 i nums.length我们可以将nums[i]的值修改为范围在[nums[i] - k, nums[i] k]内的任意整数。该操作最多只能进行一次。 我们的目标是通过修改或不修改数组中的每个元素使得修改后数组的“最大值”与“最小值”之间的差值最小化。 请你返回在执行上述操作后数组可能的最小差值。示例 1输入nums [1], k 0 输出0 解释数组只有一个元素最大值和最小值都是1差值为0。示例 2输入nums [0, 10], k 2 输出6 解释可以将数组修改为 [2, 8]。最大值8与最小值2的差值为6。示例 3输入nums [1, 3, 6], k 3 输出0 解释可以将数组修改为 [3, 3, 3]。最大值和最小值相等差值为0。1.2 核心概念什么是“最小差值”这道题的核心在于理解“操作”的实质。题目允许我们对数组中的每一个元素独立地进行一次调整调整的范围是以该元素原始值为中心上下浮动k个单位。这意味着对于任意一个元素nums[i]其最终可能的值是一个区间[nums[i] - k, nums[i] k]。我们的目标是通过为每个元素在这个区间内选择一个最终值使得整个数组的最大值与最小值的差尽可能小。这听起来像是一个复杂的组合优化问题但如果我们深入思考其数学本质会发现一个非常简洁的规律。1.3 为什么这道题值得学习思维转换它训练你将一个看似需要遍历所有可能性的问题转化为一个基于极值的数学计算问题。理解极值深刻理解数组的“最大值”和“最小值”在允许波动下的行为。面试高频这类考察数学思维和问题简化能力的题目在笔试和面试中非常常见。代码简洁最优解法通常只需要几行代码是体现算法功力的好题目。2. 解题思路分析与数学推导直接对每个元素进行枚举修改显然是不现实的。我们需要找到问题的关键。2.1 思路启发考虑两个极端情况让我们先考虑数组中的两个特殊元素原始数组的最大值max_num和最小值min_num。对于最小值min_num我们最多能将它增加k变为min_num k。对于最大值max_num我们最多能将它减少k变为max_num - k。我们的核心目标是缩小max_num和min_num之间的距离。2.2 数学推导与核心公式设原始数组的最大值为max_val最小值为min_val。在允许修改的情况下可能的最小值是多少最小值min_val最多只能增加到min_val k。因此整个数组修改后可能的最小值new_min至少是min_val但我们可以尝试让它变大最大不会超过min_val k。实际上new_min可以是min_val到min_val k之间的任意值但为了缩小与最大值的差距我们通常希望new_min尽可能大。同理可能的最大值是多少最大值max_val最多只能减少到max_val - k。因此整个数组修改后可能的最大值new_max至多是max_val但我们可以尝试让它变小最小不会低于max_val - k。为了缩小差距我们通常希望new_max尽可能小。那么最优策略是什么我们努力让最小值变大让最大值变小。如果它们调整后的范围有重叠我们甚至可以让它们相等调整后的最小值范围[min_val, min_val k]调整后的最大值范围[max_val - k, max_val]如果(min_val k) (max_val - k)说明这两个区间有重叠。我们完全可以选择一个值让它同时落在两个区间内从而使new_min等于new_max。此时最小差值就是0。如果(min_val k) (max_val - k)说明无论我们怎么调整最小值能到达的最高点仍然低于最大值能到达的最低点。它们之间始终存在一个“无法跨越的鸿沟”。此时我们最优的做法是将最小值提升到最高 (min_val k)将最大值降低到最低 (max_val - k)。此时的最小差值就是(max_val - k) - (min_val k) max_val - min_val - 2 * k。综上所述最小差值的计算公式为max(0, (max_val - min_val) - 2 * k)这个max(0, ...)确保了当差值可能为负数时即区间重叠时我们取0。2.3 思路验证用之前的例子验证示例1:nums[1], k0。max_val1, min_val1。差值 max(0, (1-1) - 2*0) max(0, 0) 0。正确。示例2:nums[0,10], k2。max_val10, min_val0。差值 max(0, (10-0) - 2*2) max(0, 10-4) max(0, 6) 6。正确。示例3:nums[1,3,6], k3。max_val6, min_val1。差值 max(0, (6-1) - 2*3) max(0, 5-6) max(0, -1) 0。正确。3. 环境准备与代码实现3.1 环境说明编程语言Python 3.x。本题解不依赖任何第三方库使用Python内置函数即可。代码编辑器/IDE任意你熟悉的工具即可如 VS Code, PyCharm, Jupyter Notebook。力扣刷题环境你可以在力扣官网直接使用其在线编辑器。3.2 核心函数实现根据上述推导代码实现极其简洁。我们只需要找到数组的最大值和最小值然后套用公式即可。class Solution: def smallestRangeI(self, nums: List[int], k: int) - int: 计算执行操作后数组可能的最小差值。 参数: nums (List[int]): 输入的整数数组。 k (int): 允许每个元素调整的最大幅度。 返回: int: 可能的最小差值。 # 步骤1: 找到数组中的最大值和最小值 max_val max(nums) min_val min(nums) # 步骤2: 应用核心公式计算最小差值 # max(0, (原始极差) - 2*k) result max(0, (max_val - min_val) - 2 * k) return result3.3 代码逐行解析def smallestRangeI(self, nums: List[int], k: int) - int:这是力扣题目要求的函数签名包含类型注解清晰明了。max_val max(nums)和min_val min(nums)使用Python内置的max()和min()函数以O(n)的时间复杂度遍历数组一次实际上max()和min()各遍历一次总体仍是 O(n)找到极值。这是效率最高的方法。result max(0, (max_val - min_val) - 2 * k)这是算法的核心。max_val - min_val计算原始数组的极差。减去2 * k表示我们试图通过调整将极差缩小2k最小值加k最大值减k。max(0, ...)确保结果非负。如果计算出的差值为负说明极差可以完全消除最小差值就是0。return result返回计算结果。3.4 复杂度分析时间复杂度O(n)。其中 n 是数组nums的长度。我们只需要遍历数组两次分别求最大值和最小值或者一些优化实现可以一次遍历同时找到最大最小值但复杂度仍是 O(n)。空间复杂度O(1)。我们只使用了常数级别的额外空间几个变量与输入数组的大小无关。4. 测试用例与运行验证为了确保代码的正确性我们需要设计多种边界情况和典型场景进行测试。# 测试代码 def test_smallestRangeI(): solution Solution() # 测试用例1: 单元素数组k0 assert solution.smallestRangeI([1], 0) 0, 测试用例1失败 print(测试用例1通过: nums[1], k0 - 0) # 测试用例2: 示例2 assert solution.smallestRangeI([0, 10], 2) 6, 测试用例2失败 print(测试用例2通过: nums[0,10], k2 - 6) # 测试用例3: 示例3差值可降为0 assert solution.smallestRangeI([1, 3, 6], 3) 0, 测试用例3失败 print(测试用例3通过: nums[1,3,6], k3 - 0) # 测试用例4: 所有元素相同k任意 assert solution.smallestRangeI([5, 5, 5, 5], 10) 0, 测试用例4失败 print(测试用例4通过: nums[5,5,5,5], k10 - 0) # 测试用例5: k非常大足以让任何元素变成任何值相对而言 # 原始极差为 100-199 2*k 200 99-200 -101 max(0, -101)0 assert solution.smallestRangeI([1, 50, 100], 100) 0, 测试用例5失败 print(测试用例5通过: nums[1,50,100], k100 - 0) # 测试用例6: k0即不允许修改 assert solution.smallestRangeI([4, 7, 2, 9], 0) 7, 测试用例6失败 # 9-27 print(测试用例6通过: nums[4,7,2,9], k0 - 7) # 测试用例7: 普通情况差值不能降为0 # 极差90-1080, 2*k30, 80-3050 assert solution.smallestRangeI([10, 30, 60, 90], 15) 50, 测试用例7失败 print(测试用例7通过: nums[10,30,60,90], k15 - 50) print(\n所有测试用例通过) # 运行测试 if __name__ __main__: # 注意需要将上面的Solution类定义包含进来 test_smallestRangeI()将上述测试代码与Solution类放在同一个文件中运行你会看到所有测试通过的输出。这验证了我们算法逻辑的正确性。5. 常见错误与思维误区在解决这道题时初学者容易陷入以下几个误区5.1 误区一尝试修改所有元素的值错误想法“我需要为每个nums[i]决定一个具体的修改值然后计算新数组的极差再找最小值。”分析这种思路会导致组合爆炸。数组有n个元素每个元素有(2k1)种可能如果k小搜索空间巨大。题目并没有要求输出具体的修改方案只要求最小差值因此这是一个典型的优化问题往往存在数学规律无需枚举。5.2 误区二只关注最大值和最小值但策略错误错误想法“我把最大值减小k最小值增加k然后计算新差值(max-k) - (mink)就行了。”分析这个想法接近了但忽略了关键情况——当(max - k)可能小于(min k)时计算出的差值会是负数这在实际的差值中是没有意义的。差值最小就是0。因此必须用max(0, ...)来保证结果的正确性。这是本题最易错的点。5.3 误区三使用排序错误代码示例def smallestRangeI_wrong(nums, k): nums.sort() # 不必要的排序O(n log n) 复杂度 return max(0, (nums[-1] - nums[0]) - 2*k)分析虽然这段代码能得到正确结果但其时间复杂度是O(n log n)因为排序操作。而通过max()和min()函数只需要O(n)的时间。在算法题中应选择最优解法。排序在这里是多余且低效的。5.4 误区四误解“最多进行一次操作”错误理解认为整个数组只能修改一次或者每个元素只能被修改一次但必须选择同一个k值。正确理解题目意思是对于每个下标 i你可以选择对 nums[i] 进行一次修改操作修改到其允许的范围内也可以选择不修改。并且每个元素的操作是独立的。k是一个全局参数定义了每个元素允许修改的幅度。6. 进阶思考与变式题目理解了「最小差值 I」的本质后我们可以思考一些相关的变式问题以巩固这种数学思维。6.1 变式最小差值 II (Leetcode 910)这是第908题的强化版Leetcode 910题。题目变为 对于每个整数nums[i]我们可以选择将其变为nums[i] k或nums[i] - k。 目标是同样使得修改后数组的极差最小。区别在“最小差值 I”中元素可以变为区间内的任意值在“最小差值 II”中元素只有两种选择加k或减k。这大大增加了难度因为无法通过“微调”让所有值汇聚到一点。解决它通常需要排序和枚举分割点的思路时间复杂度为 O(n log n)。建议在掌握本题后挑战。6.2 思维扩展如何证明公式的正确性我们可以更形式化地证明max(0, max_val - min_val - 2*k)是最优解。下界Lower Bound无论我们如何修改新的最大值new_max至少是max_val - k因为最大值最多减k新的最小值new_min至多是min_val k因为最小值最多加k。因此极差new_max - new_min至少是(max_val - k) - (min_val k) max_val - min_val - 2k。又因为极差非负所以最小可能差值是max(0, max_val - min_val - 2k)。可达性Achievability我们可以构造一个修改方案来达到这个下界。如果max_val - min_val - 2k 0我们可以让所有元素都修改为同一个值例如(max_val min_val) / 2的附近整数只要落在每个元素的允许区间内即可使极差为0。如果max_val - min_val - 2k 0我们可以将最大值改为max_val - k最小值改为min_val k其他元素在其区间内任意选择例如保持不变即可达到极差max_val - min_val - 2k。 这就证明了我们找到的下界是可以达到的因此它就是最优解。7. 在力扣上的提交与优化7.1 直接提交将我们实现的Solution类代码复制到力扣的代码编辑器中点击提交通常可以轻松通过所有测试用例并且时间复杂度和空间复杂度都是最优的。7.2 一行代码版本Pythonic写法Python的简洁性允许我们将代码写得非常短但这可能会牺牲一些可读性。仅供欣赏和参考class Solution: def smallestRangeI(self, nums: List[int], k: int) - int: return max(0, max(nums) - min(nums) - 2 * k)点评虽然极其简洁但在面试或团队协作中更推荐使用带有清晰变量名和注释的版本便于他人理解和维护。7.3 一次遍历求极值我们之前的代码调用了两次内置函数max()和min()理论上Python可能会遍历数组两次。我们可以手动实现一次遍历同时找到最大值和最小值这在某些对常数项要求极高的场景下可能略有优势但对于此题内置函数已经足够高效且代码更清晰。class Solution: def smallestRangeI(self, nums: List[int], k: int) - int: min_val float(inf) max_val float(-inf) for num in nums: if num min_val: min_val num if num max_val: max_val num return max(0, max_val - min_val - 2 * k)8. 总结与刷题建议力扣第908题「最小差值 I」是一道优秀的数学思维题。它教会我们面对算法问题时不要急于编码而应先深入分析问题本质寻找数学规律或简化模型。回顾核心要点问题转化将“为每个元素选择修改值”的复杂问题转化为对数组原始最大值和最小值的调整问题。关键公式最小差值 max(0, (原始最大值 - 原始最小值) - 2 * k)。核心逻辑努力提升最小值降低最大值。如果它们调整后的范围有交集差值为0否则差值即为调整后范围之间的距离。刷题建议举一反三解决此题后立即去尝试它的进阶版「最小差值 II」Leetcode 910体会条件变化如何导致解法完全不同。归类总结将此类问题归类为“极值/范围调整”问题。类似的题目还有一些贪心或数学问题其核心都是通过分析边界条件来得到最优解。复杂度意识即使像本题这样输入规模可能不大也要养成寻找最优时间、空间复杂度解法的习惯。测试驱动编写代码时像第4节那样自己设计测试用例覆盖边界情况空数组本题不存在、单元素、k0、k极大等情况能极大提高代码正确率和一次通过率。掌握这道题不仅仅是解决了一个具体的算法问题更是获得了一种重要的解题思维从最极端的元素入手分析它们的变化范围从而推导出全局最优解。这种思维在解决许多优化问题时都非常有用。希望这篇详细的解析能帮助你彻底理解此题并在未来的刷题道路上更加顺利。

相关新闻

2026/8/25 3:29:24

基于SpringBoot的校园食堂就餐推荐系统(程序+文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/25 3:29:24

大模型工具调用全解析:从原理到安全实践,构建智能助手核心能力

1. 先搞清楚“工具调用”到底在解决什么问题如果你正在接触大模型应用开发,尤其是想让它帮你查天气、订机票、发邮件,或者连接数据库、调用外部API,那你一定会遇到“工具调用”这个概念。很多人一上来就去看代码,结果被各种框架、…

2026/8/25 3:29:24

数据末日求生指南:备份恢复终极检查清单,帮助企业防患于未然

数据备份与恢复流程对于业务连续性至关重要。每个企业或个人都需要一个计划和程序来备份、保护和恢复其数据。本文提供了一个简单的检查清单,可作为模板,确保用户的文件和数据永不丢失。备份中应包含哪些文件任何备份计划中首要且可以说最重要的部分&…

2026/8/25 5:59:35

OpenAI API密钥级用量追踪:精细化成本管理与多项目分摊实战

这次我们来看一个对开发者、团队和公司财务都至关重要的功能更新:OpenAI 支持按 API 密钥追踪用量与支出。对于任何将 OpenAI 的 GPT、DALLE、Whisper 等模型集成到产品、服务或内部工作流中的用户来说,成本控制和管理都是一个核心痛点。过去&#xff0c…

2026/8/25 5:59:35

机器视觉采用Jakarta EE 和Python深度学习框架的技术方案

如果要为现有的 Jakarta EE 11 业务应用(采用经典的 JSF EJB JPA 三层架构)增加一个类似 IBM Maximo 的机器视觉(模型训练与推理)模块,最核心的原则是“业务归 Java,AI 归 Python,通过微服务/…

2026/8/25 5:59:35

AI Agent从副驾驶到代理人:打通支付闭环的技术架构与挑战

1. 项目概述:当AI Agent开始“掏钱”最近,一个名为“龙虾”的OpenClaw项目,与支付宝的AI付功能进行了一次引人注目的结合尝试。这听起来可能有点抽象,但简单来说,就是让AI智能体(Agent)不再仅仅…

2026/8/25 5:59:35

Java后端面试高频考点与深度解析

1. Java后端高频面试题整理的必要性作为Java后端开发者,面试准备是职业生涯中无法回避的重要环节。我整理这份高频面试题集的初衷很简单:市面上虽然有不少面试题库,但要么过于零散不成体系,要么内容陈旧跟不上技术发展。更重要的是…

2026/8/25 5:59:35

LangChain Agent集成MCP协议:实现AI工具即插即用的标准化方案

如果你正在开发AI Agent,可能已经遇到了这样的瓶颈:Agent能理解你的指令,也能调用几个基础工具,但一旦需要连接数据库、读取文件、调用第三方API,就得写大量胶水代码。更头疼的是,每个新工具都得重新集成、…

2026/8/25 1:04:19

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/24 1:12:32

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/24 8:17:29

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/25 0:04:14

三步把QQ空间历史说说导出到本地:GetQzonehistory 极简指南

三步把QQ空间历史说说导出到本地:GetQzonehistory 极简指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory Meta Description:GetQzonehistory 是一个QQ空间历史说…

2026/8/25 0:04:14

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

【题目来源】 https://www.luogu.com.cn/problem/P7912 【题目描述】 小熊的水果店里摆放着一排 n 个水果。每个水果只可能是苹果或桔子,从左到右依次用正整数 1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里&#x…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/25 1:08:14

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…