【算法题】最少侧跳次数 —— 青蛙过三跑道障碍问题详解
题目描述
给你一条长度为 n 的道路,道路有 3 条跑道,总共包含 n + 1 个点,编号从 0 到 n。青蛙从起点 0 处的 第 2 条跑道 出发,目标是跳到第 n 号点的任意一条跑道。
道路上可能存在障碍。用一个长度为 n + 1 的数组 obstacles 表示:
obstacles[i]的取值范围是 0 到 3。- 如果
obstacles[i] = k(k != 0),则表示第 i 个点的第 k 条跑道上有一个障碍。 - 如果
obstacles[i] = 0,则该点所有跑道无障碍。
题目要求:
- 青蛙可以从点 i 的某条跑道跳到点 i+1 同跑道(如果没有障碍)。
- 青蛙也可以在同一点 i 处,侧跳(换跑道),条件是换过去的跑道在该点没有障碍。
- 青蛙从点 0 的第 2 跑道出发,想跳到点 n 任意跑道,求 最少侧跳次数。
注意:点 0 和点 n 的任意跑道均无障碍。
题目示例
假设 obstacles = [0,1,2,3,0] 表示:
- 点0无障碍
- 点1第1条跑道有障碍
- 点2第2条跑道有障碍
- 点3第3条跑道有障碍
- 点4无障碍
青蛙从点0跑道2出发,要跳到点4,避免障碍,最少侧跳次数是多少?
解题分析
这道题的关键在于:
- 青蛙想尽量少侧跳;
- 只能向前跳到下一点同跑道上无障碍的位置;
- 如果前方受阻,可以在当前点换跑道(侧跳),但不能跳到有障碍的跑道。
思考方式
- 起点在点0跑道2,侧跳次数为0。
- 如果下一点同跑道无障碍,可以直接跳,不用侧跳。
- 如果下一点有障碍,就必须在当前点换跑道侧跳,再继续跳。
- 目标是求最少侧跳次数。
解题方法
使用动态规划(DP)或贪心策略模拟每个点每条跑道的最少侧跳次数。
状态定义
- 设
dp[i][j]表示到达第 i 个点,处于第 j 条跑道时的最少侧跳次数。 - 跑道编号
j范围是 1~3。 - 青蛙从
(0,2)出发,因此:dp[0][2] = 0- 其他跑道初始为
∞(或者可以设为1,表示必须侧跳一次)
状态转移
对于点 i (从 0 到 n-1):
- 先检查点 i+1 各跑道是否有障碍:
- 如果
obstacles[i+1] == j,跑道 j 不可用,dp[i+1][j] = ∞。 - 否则,可以尝试:
- 如果从跑道 j 的 dp[i][j] 可达,则
dp[i+1][j] = dp[i][j](直接跳,无需侧跳)。
- 如果从跑道 j 的 dp[i][j] 可达,则
- 如果
- 对于当前点 i ,考虑侧跳:
- 对于跑道 j,尝试从其他两条跑道侧跳过来,侧跳次数 +1。
- 更新
dp[i][j] = min(dp[i][j], dp[i][k] + 1),其中 k != j。
状态压缩优化
因为我们只用到前一个点的信息,可以用一维数组 dp[j] 表示当前点处第 j 条跑道的最少侧跳次数。
- 初始:
dp = [∞, 1, 0, 1](下标0不用)
- 每处理一个点 i:
- 设置
dp[obstacles[i]] = ∞表示该跑道被障碍阻断不可达 - 找出当前 dp 中的最小值
min_dp - 对未阻断的跑道
j更新:dp[j] = min(dp[j], min_dp + 1)表示可以侧跳过来
- 设置
代码实现
from typing import List
class Solution:
def minSideJumps(self, obstacles: List[int]) -> int:
n = len(obstacles) - 1
dp = [float('inf')] * 4
# 起点0跑道2侧跳次数0,跑道1和3各需要1次侧跳跳过来
dp[1], dp[2], dp[3] = 1, 0, 1
for i in range(1, n + 1):
# 把有障碍的跑道设为不可达
dp[obstacles[i]] = float('inf')
# 找当前点所有跑道的最小侧跳次数
min_dp = min(dp[1], dp[2], dp[3])
# 更新其他跑道侧跳次数(可能通过侧跳变得更小)
for j in range(1, 4):
if obstacles[i] != j:
dp[j] = min(dp[j], min_dp + 1)
return min(dp[1], dp[2], dp[3])
复杂度分析
- 时间复杂度:O(n),遍历一次 obstacles 数组,每个点处理3条跑道的状态更新。
- 空间复杂度:O(1),使用长度为4的一维 dp 数组,空间使用固定。
示例讲解
以 obstacles = [0,1,2,3,0] 为例:
- 起点:dp = [∞,1,0,1]
- 点1障碍在跑道1,
dp[1] = ∞- 计算当前最小侧跳次数 = min(dp) = 0
- 其他跑道更新为 min(dp[j], 0 + 1) 即 dp[2] = 0, dp[3] = 1
- 点2障碍跑道2,
dp[2] = ∞- 最小侧跳次数是 min(∞, ∞, 1) = 1
- dp[1] = min(∞, 1+1=2) = 2, dp[3] = 1 (保持不变)
- 点3障碍跑道3,
dp[3] = ∞- 最小侧跳次数是 min(2, ∞, ∞) = 2
- dp[1] = 2, dp[2] = min(∞, 2+1=3) = 3
- 点4无障碍
- 最小侧跳次数是 min(2, 3, ∞) = 2
- 更新dp[1], dp[2], dp[3] 最小分别为 2, 3, 3
最终最小值是2,表示青蛙至少要侧跳2次才能到达点4。
总结
本题核心考察对状态转移的理解与优化。通过维护每个点上三条跑道的最少侧跳次数,动态规划可以高效求解问题。状态压缩使得空间复杂度降为常数。
4412

被折叠的 条评论
为什么被折叠?



