news 2026/5/3 15:12:24

【LeetCode详解】在下标间移动的最小代价(贪心+前缀和 O(n+q) 多解法超详解析)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【LeetCode详解】在下标间移动的最小代价(贪心+前缀和 O(n+q) 多解法超详解析)

【LeetCode 】在下标间移动的最小代价(贪心+前缀和 O(n+q) 多解法超详解析)

目录

  • 问题描述

  • 示例分析

  • 思路过程

    • 解法一:暴力建图 + 最短路(不可行)

    • 解法二:观察单调性与贪心策略

    • 解法三:前缀和优化(最终最优解)

  • 算法详解

    • Step1:计算 closest 数组

    • Step2:定义方向代价

    • Step3:前缀和预处理

    • Step4:O(1) 回答每个查询

  • 完整代码实现

  • 复杂度分析

  • 单调性正确性证明

  • 测试与验证

  • 总结与扩展

1. 问题描述

给你一个严格递增的整数数组nums

对于每个下标x,定义closest\(x\)为使得abs\(nums\[x\] \- nums\[y\]\)最小化的相邻下标

特殊规则:如果左右相邻下标差值相同,则选择更小的下标

你拥有两种移动方式:

  1. 任意瞬移:从下标x移动到任意下标y,代价为abs\(nums\[x\] \- nums\[y\]\)

  2. 捷径移动:从下标x移动到closest\(x\),固定代价为1

给定二维查询数组queries,每个查询\[li, ri\]代表从下标li移动到ri,求每次移动的最小总代价

约束条件

  • 2 \<= nums\.length \<= 10^5

  • \-10^9 \<= nums\[i\] \<= 10^9nums严格递增

  • 1 \<= queries\.length \<= 10^5

  • 0 \<= li, ri \< nums\.length

2. 示例分析

示例 1

输入:nums = [-5,-2,3], queries = [[0,2],[2,0],[1,2]] 输出:[6,2,5]

预处理得到closest = \[1, 0, 1\]

  • 查询\[0,2\]:0→1(捷径代价1)+ 1瞬移→2(代价5),总代价 6

  • 查询\[2,0\]:2→1(代价1)+ 1→0(代价1),全程捷径,总代价 2

  • 查询\[1,2\]:直接瞬移代价5,优于捷径绕路,总代价 5

示例 2

输入:nums = [0,2,3,9], queries = [[3,0],[1,2],[2,0]] 输出:[4,1,3]

预处理得到closest = \[1, 2, 1, 2\]

  • 查询\[3,0\]:3→2(1) + 2→1(1) + 1瞬移→0(2),总代价 4

  • 查询\[1,2\]:直接捷径移动,代价 1

  • 查询\[2,0\]:2→1(1) + 1瞬移→0(2),总代价 3

核心规律:最优路径不存在折返,始终沿起点到终点的方向单调移动。

3. 思路过程

3.1 解法一:暴力建图 + 最短路(不可行)

思路原理

将数组每个下标视为图的节点,构建两类边:

  1. 全连接瞬移边:任意节点i→j,代价为数值绝对差

  2. 捷径边:i→closest\(i\),固定代价 1

对每个查询,使用 Dijkstra 算法求解单点最短路。

致命缺陷
  • 全连接边数量为O ( n 2 ) O(n^2)O(n2),无法存储与遍历

  • n 、 q ≤ 10 5 n、q \le 10^5nq105,单次 DijkstraO ( n log ⁡ n ) O(n\log n)O(nlogn),总复杂度爆炸超时

结论:暴力最短路仅适用于教学理解,无法通过大数据测试。

3.2 解法二:观察单调性与贪心策略

核心观察

数组严格递增,数值差满足三角不等式:折返移动会额外增加数值代价,捷径的1点代价节省无法弥补折返损耗。

因此最优路径一定单调不折返

  • 起点l \< r:只向右移动

  • 起点l \> r:只向左移动

贪心策略

相邻两点移动时,永远选择最小代价:

  • 若当前节点捷径指向前进方向,代价为1

  • 否则使用瞬移代价(数值差值)

3.3 解法三:前缀和优化(最终最优解)

基于贪心单调性,预处理左右方向相邻最小代价,再通过前缀和数组预处理区间代价,最终实现O(1) 单次查询,整体复杂度O ( n + q ) O(n+q)O(n+q),完美适配 1e5 极限数据。

4. 算法详解

4.1 Step1:计算 closest 数组

根据题目规则,遍历每个下标求解最近相邻下标:

  • 首位下标i=0:无左邻居,closest\[0\] = 1

  • 末位下标i=n\-1:无右邻居,closest\[n\-1\] = n\-2

  • 中间下标:对比左右差值,左差值≤右差值选左,否则选右(差值相等选小下标)

n=len(nums)closest=[0]*n closest[0]=1closest[n-1]=n-2foriinrange(1,n-1):left_diff=nums[i]-nums[i-1]right_diff=nums[i+1]-nums[i]ifleft_diff<=right_diff:closest[i]=i-1else:closest[i]=i+1

4.2 Step2:定义方向代价

定义两个代价数组,存储相邻两点的最小移动代价:

  • R\[i\]:从i向右走到i\+1的最小代价

  • L\[i\]:从i向左走到i\-1的最小代价

代价规则:捷径指向目标下标则代价为1,否则为数值差值。

# 向右代价 R[i]: i -> i+1R=[0]*(n-1)foriinrange(n-1):ifclosest[i]==i+1:R[i]=1else:R[i]=nums[i+1]-nums[i]# 向左代价 L[i]: i -> i-1L=[0]*nforiinrange(1,n):ifclosest[i]==i-1:L[i]=1else:L[i]=nums[i]-nums[i-1]

4.3 Step3:前缀和预处理

构建前缀和数组,快速求解任意区间的累计最小代价:

  • prefR\[i\]:前i个向右代价的前缀和,用于查询右行区间

  • prefL\[i\]:前i个向左代价的前缀和,用于查询左行区间

prefR=[0]*nforiinrange(n-1):prefR[i+1]=prefR[i]+R[i]prefL=[0]*nforiinrange(1,n):prefL[i]=prefL[i-1]+L[i]

4.4 Step4:O(1) 回答每个查询

根据起点终点大小关系,直接通过前缀和差值计算答案:

  • l \&lt; r:右行,代价prefR\[r\] \- prefR\[l\]

  • l \&gt; r:左行,代价prefL\[l\] \- prefL\[r\]

  • l == r:无需移动,代价 0

5. 完整代码实现

classSolution:defminCost(self,nums:list[int],queries:list[list[int]])->list[int]:# ©leetcoden=len(nums)ifn<=1:return[0]*len(queries)# Step1: 预处理closest数组closest=[0]*n closest[0]=1closest[-1]=n-2foriinrange(1,n-1):left_diff=nums[i]-nums[i-1]right_diff=nums[i+1]-nums[i]ifleft_diff<=right_diff:closest[i]=i-1else:closest[i]=i+1# Step2: 预处理左右相邻移动最小代价R=[0]*(n-1)foriinrange(n-1):ifclosest[i]==i+1:R[i]=1else:R[i]=nums[i+1]-nums[i]L=[0]*nforiinrange(1,n):ifclosest[i]==i-1:L[i]=1else:L[i]=nums[i]-nums[i-1]# Step3: 构建前缀和数组prefR=[0]*nforiinrange(n-1):prefR[i+1]=prefR[i]+R[i]prefL=[0]*nforiinrange(1,n):prefL[i]=prefL[i-1]+L[i]# Step4: O(1)应答所有查询res=[]forl,rinqueries:ifl==r:res.append(0)elifl<r:res.append(prefR[r]-prefR[l])else:res.append(prefL[l]-prefL[r])returnres

6. 复杂度分析

执行步骤时间复杂度空间复杂度
计算 closest 数组O(n)O(n)
构建左右代价数组O(n)O(n)
构建前缀和数组O(n)O(n)
处理所有查询O(q)O(1)
整体复杂度O(n + q)O(n)

该算法为本题最优时间复杂度,可完全通过 1e5 极限数据。

7. 单调性正确性证明

定理:任意起点到终点的最小代价路径,一定是下标单调路径(无折返)。

证明过程

数组严格递增,数值差满足三角不等式:∣ a − c ∣ ≤ ∣ a − b ∣ + ∣ b − c ∣ |a-c| \le |a-b| + |b-c|acab+bc

假设存在一条最优路径存在折返(先右后左 / 先左后右):

折返操作会额外累加两段数值差值,而捷径的固定代价1,仅能节省单次差值开销,无法抵消折返带来的额外数值代价

因此,任意含折返的路径,均可通过去除折返、改为单调直走,得到一条代价更小或相等的路径。

综上:最优路径一定单调无折返,贪心策略成立。QED

8. 测试与验证

编写测试用例,验证官方样例与边界数据:

if__name__=="__main__":sol=Solution()# 官方样例1nums1=[-5,-2,3]q1=[[0,2],[2,0],[1,2]]print(sol.minCost(nums1,q1))# 输出 [6,2,5]# 官方样例2nums2=[0,2,3,9]q2=[[3,0],[1,2],[2,0]]print(sol.minCost(nums2,q2))# 输出 [4,1,3]# 边界测试:相同起点终点print(sol.minCost([1,3,5],[[1,1],[0,0]]))# [0,0]

所有测试用例完全匹配标准答案,算法逻辑无误。

9. 总结与扩展

核心解题思路总结

  1. 摒弃暴力思维:拒绝图论最短路暴力解法,挖掘题目隐藏单调性性质。

  2. 问题转化:将复杂的双规则移动,转化为相邻节点最小代价遍历。

  3. 前缀和优化:预处理区间代价,将多次查询复杂度降为 O(1)。

算法拓展

  • closest规则修改为「差值最小任意下标」,仍可沿用单调性+前缀和框架,仅需修改预处理逻辑。

  • 若新增多种移动代价规则,可通过「预处理所有相邻最小代价+前缀和」的通用思路求解。

CSDN原创声明:本文为博主原创技术分享,详解LeetCode中等偏上贪心+前缀和算法题,包含多解法对比、数学证明、完整可运行代码,转载请注明出处。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 15:10:43

Word论文党必看:用页眉插入背景图,完美解决转PDF图片重叠的坑

Word论文排版进阶&#xff1a;页眉插入背景图解决PDF导出重叠问题 对于学术写作和商务报告而言&#xff0c;文档的视觉呈现与内容质量同等重要。许多用户在Word中精心设计的背景图案&#xff0c;在转换为PDF时却遭遇图片错位、重复堆叠的尴尬。这种技术痛点不仅影响专业形象&am…

作者头像 李华
网站建设 2026/5/3 15:10:28

如何在Windows上安装APK文件:APK-Installer极简教程与使用指南

如何在Windows上安装APK文件&#xff1a;APK-Installer极简教程与使用指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 在Windows电脑上直接安装APK文件曾经是技术人…

作者头像 李华
网站建设 2026/5/3 15:09:37

告别终端黑框!用VSCode插件高效开发ROS(附Python/C++配置避坑)

告别终端黑框&#xff01;用VSCode插件高效开发ROS&#xff08;附Python/C配置避坑&#xff09; 在机器人操作系统&#xff08;ROS&#xff09;开发中&#xff0c;许多开发者长期忍受着频繁切换终端、缺乏智能提示和调试困难的困扰。传统开发方式需要在多个黑框终端中运行rosc…

作者头像 李华
网站建设 2026/5/3 15:08:38

百度网盘Mac版破解插件:一键解锁SVIP高速下载的完整指南

百度网盘Mac版破解插件&#xff1a;一键解锁SVIP高速下载的完整指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 百度网盘作为国内用户量最大的云存…

作者头像 李华
网站建设 2026/5/3 15:05:21

Steam游戏清单下载终极指南:3分钟解锁完整游戏库

Steam游戏清单下载终极指南&#xff1a;3分钟解锁完整游戏库 【免费下载链接】Onekey Onekey Steam Depot Manifest Downloader 项目地址: https://gitcode.com/gh_mirrors/one/Onekey 还在为Steam游戏下载速度慢而烦恼吗&#xff1f;想要备份游戏却不知从何下手&#x…

作者头像 李华