带顺序跳跃的网格最短路径遍历实现修复与提速咨询
网格最短路径问题解答
问题梳理
从网格左下角(0,0)出发到右上角(X-1,Y-1),合法移动规则为:向右移动1格、向上移动1格、按给定jumps数组顺序依次完成向上/向右跳跃(跳跃步长为jump值+1格,跳过的中间格子不计入路径和),路径总长度为途经所有格子数值之和,要求输出最短路径总长度。
示例输入:
Grid: [9 9 1] [9 9 1] [3 9 1] Jumps: [1 1] X:3, Y:3
对应输出为5,逻辑如题干所述。
现有代码问题分析
第一版递归解法问题
你的第一版递归本质是暴力DFS,存在大量重复子问题,时间复杂度为指数级,网格稍大就会超时甚至无法终止。同时没有显式记录已使用的跳跃次数,递归状态不完整,实际运行中也可能出现逻辑错误。
第二版DP解法问题
存在三个核心错误:
- 状态维度缺失:跳跃需要按顺序使用,同一坐标(y,x)在已使用k个跳跃和已使用m个跳跃的场景下,最小路径和完全不同,你只用二维DP存储坐标维度,丢失了跳跃使用进度的关键状态。
- 全局修改jumps数组逻辑错误:不同路径使用跳跃的时机不同,你直接全局修改jumps数组,相当于所有路径共享同一个跳跃使用进度,完全不符合实际场景。
- 语法逻辑错误:判断
if min == jumpup or min == jumpright中的min是Python内置函数,你实际要比较的是前面计算得到的shortest变量,这里的判断完全不生效。
高效实现方案
这里提供修正后的三维DP方案,时间复杂度为O(KXY),其中K为jumps数组长度,完全可以应对中等规模以上的输入:
三维DP思路
定义三维状态dp[k][y][x]:表示已使用前k个跳跃,到达坐标(y,x)时的最小路径和。
- 初始化:所有状态初始化为无穷大,起点状态
dp[0][0][0] = grid[0][0] - 状态转移:
- 普通移动:对于任意状态
dp[k][y][x],向上走1格到(y+1,x),可更新dp[k][y+1][x] = min(dp[k][y+1][x], dp[k][y][x] + grid[y+1][x]);向右走1格到(y,x+1),可更新dp[k][y][x+1] = min(dp[k][y][x+1], dp[k][y][x] + grid[y][x+1]) - 跳跃移动:如果k < len(jumps),可以使用第k个跳跃:向上跳
jumps[k]+1格到y + jumps[k] + 1,如果不越界,可更新dp[k+1][y + jumps[k] + 1][x] = min(dp[k+1][y + jumps[k] + 1][x], dp[k][y][x] + grid[y + jumps[k] + 1][x]);向右跳同理。
- 普通移动:对于任意状态
- 最终结果:所有
dp[k][Y-1][X-1](k的取值范围是0到len(jumps))中的最小值。
代码实现
def min_path_sum(grid, jumps, X, Y): K = len(jumps) INF = float('inf') # dp[k][y][x] 用了k个jump,到(y,x)的最小和 dp = [[[INF]*X for _ in range(Y)] for __ in range(K+1)] dp[0][0][0] = grid[0][0] for k in range(K+1): # 迭代更新当前k下所有坐标的最小路径和,直到没有更新 updated = True while updated: updated = False for y in range(Y): for x in range(X): if dp[k][y][x] == INF: continue # 向上走 if y + 1 < Y: if dp[k][y+1][x] > dp[k][y][x] + grid[y+1][x]: dp[k][y+1][x] = dp[k][y][x] + grid[y+1][x] updated = True # 向右走 if x + 1 < X: if dp[k][y][x+1] > dp[k][y][x] + grid[y][x+1]: dp[k][y][x+1] = dp[k][y][x] + grid[y][x+1] updated = True # 处理当前k可以跳跃的情况,生成k+1层的状态 if k < K: jump_val = jumps[k] for y in range(Y): for x in range(X): if dp[k][y][x] == INF: continue # 向上跳 new_y = y + jump_val + 1 if new_y < Y: if dp[k+1][new_y][x] > dp[k][y][x] + grid[new_y][x]: dp[k+1][new_y][x] = dp[k][y][x] + grid[new_y][x] # 向右跳 new_x = x + jump_val + 1 if new_x < X: if dp[k+1][y][new_x] > dp[k][y][x] + grid[y][new_x]: dp[k+1][y][new_x] = dp[k][y][x] + grid[y][new_x] # 取所有可能的k到达终点的最小值 return min(dp[k][Y-1][X-1] for k in range(K+1)) # 测试示例 grid = [ [3,9,1], [9,9,1], [9,9,1] ] jumps = [1,1] X=3 Y=3 print(min_path_sum(grid, jumps, X, Y)) # 输出5 jumps = [1] print(min_path_sum(grid, jumps, X, Y)) # 输出6
如果grid数值全为正数,也可以使用Dijkstra算法优化,以路径和为权重,优先队列每次取出当前最小路径和的状态扩展,首次到达终点即可直接返回结果,效率更高。
内容的提问来源于stack exchange,提问作者Pryver Johnson
相关产品推荐
相关产品推荐

