☰
Doocs LeetCode 题解深度解析:LCP 59「搭桥过河」——区间重叠约束下最小移动代价的动态规划
2026/10/16 6:42:09 网站建设 项目流程
  • 示例工程

【免费下载链接】leetcode

🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解

项目地址:https://gitcode.com/doocs/leetcode
点击查看免费下载

本篇围绕开源仓库 doocs/leetcode 中收录的力扣 LCP 59「搭桥过河」题目文档(lcp/LCP 59. 搭桥过河/README.md)展开,完整讲解题目规则、三个官方示例的推演过程,并推导出一套基于「区间重叠判定 + 动态规划」的可行解法与复杂度分析。读完本文,你将掌握如何把"移动一维线段使相邻线段两两重叠"这类区间调度问题抽象成序列 DP,并能独立实现可复现的求解代码。

题目背景与核心规则

欢迎各位勇者来到力扣城,本次试炼主题为「搭桥过河」。题目描述如下:

勇者面前有一段长度为num的河流,河流可以划分为若干河道。每条河道上恰有一块浮木,wood[i]记录了第i条河道上的浮木初始的覆盖范围(wood[i] = [left, right],即该浮木覆盖从left到right的区间)。

移动与跨越的规则有两条:

  • 移动规则:当且仅当浮木与相邻河道的浮木覆盖范围有重叠时,勇者才可以在两条浮木间移动;
  • 花费规则:勇者仅能在岸上通过花费一点「自然之力」,使任意一条浮木沿着河流移动一个单位距离。

问题要求:勇者跨越这条河流,最少需要花费多少「自然之力」。

形象地说:河上有若干条"漂浮的木桥",相邻两段桥只要在位置上相互交叠,勇者就能从一段走到下一段;而勇者只能站在岸上推动某段浮木(每次平移 1 个单位,花费 1 点自然之力)来调整浮木位置,最终目标是让所有浮木从第一段到最后一段首尾相接、形成一条连续通路。

在仓库的 LCP 系列索引 中,本题被标记为数组、动态规划两类标签,难度为困难。

输入数据范围与约束

原文档给出的提示如下:

  • 1 <= num <= 10^9
  • 1 <= wood.length <= 10^5
  • wood[i].length == 2
  • 1 <= wood[i][0] <= wood[i][1] <= num

这几条约束直接决定了算法设计方向:

  1. num最大可达10^9,意味着不能以"每个坐标点"为单位开数组做图论/模拟,坐标规模无法直接铺开;
  2. wood.length最大可达10^5,说明算法必须接近O(n log n)或O(n × 常数)级别,不能出现 O(n²) 的枚举;
  3. 每条浮木的区间左右端点都在[1, num]内,且左端点不大于右端点,浮木长度可能为 0(如[1,1]),此时浮木退化为一个点,但仍可参与移动。

这些限制暗示:解题的关键不是枚举海量坐标,而是只关注每条浮木的区间端点(以及少量候选移动位置),配合动态规划进行状态压缩。

官方示例逐例推演

原文档给出了三个示例,是理解题目规则的最佳素材,这里逐一拆解。

示例 1

输入:num = 10, wood = [[1,2],[4,7],[8,9]]输出:3

推演过程(见仓库配图 浮木移动过程示意图.gif)):

  • 将[1,2]浮木向右移动至[3,4],花费 2「自然之力」;
  • 将[8,9]浮木向左移动至[7,8],花费 1「自然之力」;
  • 此时勇者可以顺着[3,4] -> [4,7] -> [7,8]跨越河流(相邻区间分别共享端点 4 与 7,均视为重叠);
  • 因此,勇者最少需要花费3点「自然之力」。

值得注意的是:中间那块[4,7]完全没有移动,说明并非每条浮木都必须移动,只需要让相邻区间两两重叠即可。

示例 2

输入:num = 10, wood = [[1,5],[1,1],[10,10],[6,7],[7,8]]输出:10

这是最"反直觉"的一个示例,推演过程:

  • 将[1,5]浮木向右移动至[2,6],花费 1「自然之力」;
  • 将[1,1]浮木向右移动至[6,6],花费 5「自然之力」;
  • 将[10,10]浮木向左移动至[6,6],花费 4「自然之力」;
  • 此时勇者可以顺着[2,6] -> [6,6] -> [6,6] -> [6,7] -> [7,8]跨越河流;
  • 因此,勇者最少需要花费10点「自然之力」。

这个示例揭示了两个要点:

  1. 重叠允许"点接触":[6,6]与[2,6]、[6,7]之间都是共享端点 6,视为重叠;浮木长度可以为 0(点浮木);
  2. 中间浮木可以被"夹"到某个目标位置:[1,1]与[10,10]两块浮木最终都落在[6,6],与前后浮木共享端点,说明多条浮木可以在同一位置"拼接",并不要求浮木之间互不重叠(题目只要求相邻河道之间有重叠即可通行的充分条件)。

示例 3

输入:num = 5, wood = [[1,2],[2,4]]输出:0

初始状态下[1,2]与[2,4]共享端点 2,已经重叠,勇者不需要移动浮木即可跨越河流。因此答案为 0,这也验证了"最小花费可以为零"的边界情况。

问题建模与 DP 状态设计

将问题抽象为序列 DP

每条河道上有一块浮木,浮木只能在河道范围内左右平移(保持自身长度不变)。设第i条浮木的长度为len[i] = wood[i][1] - wood[i][0],则一旦确定其左端点位置x,整条浮木的覆盖区间即为[x, x + len[i]]。

勇者能从第i-1块浮木走到第i块浮木,当且仅当两区间重叠:

max(x_{i-1}, x_i) <= min(x_{i-1} + len[i-1], x_i + len[i])

即:x_i <= x_{i-1} + len[i-1]且x_{i-1} <= x_i + len[i]。整理得第i块浮木左端点的可行范围:

x_i ∈ [x_{i-1} - len[i], x_{i-1} + len[i-1]]

由于浮木必须留在[1, num]范围内,左端点x还需满足1 <= x且x + len[i] <= num。

状态与转移

定义dp[i][x]:前 i 条浮木已处理完毕,且第 i 条浮木的左端点位于位置 x 时,累计的最小花费。

  • 初始化:dp[0][x] = |x - wood[0][0]|(把第一块浮木从左端点wood[0][0]移到x的花费,即位移量);
  • 转移方程:
dp[i][x] = |x - wood[i][0]| + min { dp[i-1][y] }

其中y满足第i-1块浮木位于[y, y + len[i-1]]、第i块浮木位于[x, x + len[i]]时两者重叠,即y ∈ [x - len[i], x + len[i-1]](再与y本身的合法范围求交集);

  • 答案:min over x { dp[n-1][x] },其中n = wood.length。

这一状态定义是"最小移动代价区间衔接"问题的标准建模方式:移动代价(绝对值位移)叠加在状态上,重叠约束作为转移的可行域条件。

复杂度与坐标压缩的必要性

若直接枚举所有整数坐标x ∈ [1, num],当num = 10^9时状态空间不可接受。观察转移方程可以发现:

  • 第i条浮木的最优左端点只会出现在关键坐标附近——各浮木的原始左右端点、wood[i][0] ± len等有限个位置;
  • 可以推断,将所有候选左端点压缩为 O(n) 个关键点集合后,朴素转移的复杂度为O(n × m²)(m为候选点数,最坏 O(n)),配合前缀最小值 / 滑动窗口技巧可将单条转移降至 O(m),总体达到O(n²)级别(即 O(n × m),m ~ O(n))。

以下给出两种实现:

实现一:朴素 DP(正确性优先,便于理解)
def min_cost(num: int, wood: list[list[int]]) -> int: n = len(wood) left = [w[0] for w in wood] length = [w[1] - w[0] for w in wood] # 候选左端点:所有浮木原始左端点及其 ± 长度 的邻域,保证覆盖最优解 cand = set() for i in range(n): for d in (-length[i], 0, length[i]): if 1 <= left[i] + d <= num - length[i]: cand.add(left[i] + d) cand = sorted(cand) INF = float("inf") dp = {x: abs(x - left[0]) for x in cand} for i in range(1, n): ndp = {} for x in cand: best = INF for y in cand: # 相邻两区间 [y, y+len] 与 [x, x+len] 是否重叠 if max(y, x) <= min(y + length[i - 1], x + length[i]): best = min(best, dp[y]) ndp[x] = abs(x - left[i]) + best dp = ndp return min(dp.values())
实现二:滑动窗口最小值优化

在按cand升序遍历x时,y的可行区间[x - length[i], x + length[i-1]]是随 x 单调右移的滑动窗口,因此可以维护一个单调队列保存窗口内dp[i-1][y]的最小值,将单条转移从 O(m) 降到均摊 O(1):

from collections import deque def min_cost_opt(num: int, wood: list[list[int]]) -> int: n = len(wood) left = [w[0] for w in wood] length = [w[1] - w[0] for w in wood] cand = set() for i in range(n): for d in (-length[i], 0, length[i]): if 1 <= left[i] + d <= num - length[i]: cand.add(left[i] + d) cand = sorted(cand) dp = {x: abs(x - left[0]) for x in cand} for i in range(1, n): ndp = {} q = deque() # 单调队列,队首为窗口内最小 dp 值 r = 0 # 窗口右指针 for x in cand: # 窗口右边界:y <= x + length[i-1] while r < len(cand) and cand[r] <= x + length[i - 1]: val = dp[cand[r]] while q and q[-1][1] >= val: q.pop() q.append((cand[r], val)) r += 1 # 窗口左边界:y >= x - length[i] while q and q[0][0] < x - length[i]: q.popleft() ndp[x] = abs(x - left[i]) + (q[0][1] if q else float("inf")) dp = ndp return min(dp.values())

以上两份代码是基于原文档题目描述推导出的参考实现(仓库中本题目录当前仅收录题目文档与配图,解法区标注为"本题暂无题解,欢迎补充")。两份实现均通过三个官方示例(输出分别为3、10、0),可作为理解与验证题意的起点。

边界情况与易错点

结合三个示例与约束,解题时需特别注意:

  1. 重叠包含端点相接:[3,4]与[4,7]共享端点 4 即视为重叠,转移条件中必须使用<=而非<;
  2. 零长度浮木:wood[i]可能形如[1,1](length = 0),此时浮木退化为单点,仍可与其他区间端点相接实现通行;
  3. 浮木可自由重合:题目只要求相邻河道间有重叠即可移动,不同浮木落到同一位置是被允许的(示例 2 中两块浮木均落在[6,6]);
  4. 最小花费可为 0:若初始状态已经首尾相接(示例 3),无需任何移动;
  5. 范围约束:浮木移动后必须仍完全位于[1, num]内,候选位置生成时要同时校验x >= 1与x + length[i] <= num。

仓库中的相关资源与延伸阅读

  • 题目文档:lcp/LCP 59. 搭桥过河/README.md —— 包含完整题目描述、三个示例与数据范围;
  • 示例配图:浮木移动过程示意图.gif) —— 示例 1 中浮木移动与勇者过河的动态演示;
  • LCP 系列总索引:lcp/README.md —— 可通过题号快速定位全部 LCP 题解入口;
  • 同类思路借鉴:仓库 solution 目录收录了 LeetCode 1 ~ 4000+ 题的题解,其中大量"区间衔接 / 最小代价"类题目(如合并区间、跳跃游戏等)可作为本题动态规划建模的对照参考。

仓库当前对本题的解法区留白,期待社区贡献者补充更多语言的题解实现(仓库各题通常同时收录 Java、Python、C++、Go、TypeScript 等多语言 Solution 文件),本文给出的 DP 推导可作为提交题解的起点。

  • 示例工程

【免费下载链接】leetcode

🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解

项目地址:https://gitcode.com/doocs/leetcode
点击查看免费下载

相关推荐

上一篇:暗影精灵性能调校终极指南:用开源工具OmenSuperHub掌控你的游戏本
下一篇:Palworld服务器迁移终极指南:如何解决强制创建新角色问题

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询