一、题目描述
给定一个二维网格 grid
,其中每个单元格的值表示从该位置可以跳跃的最大步数。玩家从左上角 (0,0)
出发,每次跳跃可选择向上下左右四个方向移动,且跳跃的步数不能超过当前单元格的值。要求计算从起点到右下角 (n-1,m-1)
的最短跳跃路径长度,若无法到达则返回 -1
。
输入限制:
1 <= grid.length <= 1000
1 <= grid[0].length <= 1000
0 <= grid[i][j] <= 10^9
示例输入:
plaintext
grid = [
[2, 1, 1],
[1, 1, 1],
[1, 1, 1]
]
示例输出:2
解释:路径为 (0,0) → (0,2) → (2,2)
,共需 2 次跳跃。
二、解题思路分析
1. 常规方法的局限性
传统 BFS 算法在处理大规模网格时会因时间复杂度 O(nm)
过高而无法通过。本题的关键在于优化跳跃的方向和步数,减少无效搜索。
2. 创新算法设计
我们提出一种基于贪心 + 双向 BFS的混合策略:
- 贪心剪枝:在每一步跳跃时,优先选择能覆盖更远距离的方向,减少冗余搜索。
- 双向 BFS:同时从起点和终点出发进行搜索,当两个搜索队列相遇时,路径长度即为最短。
3. 具体实现步骤
- 方向选择:每次跳跃时,计算四个方向中能到达的最远距离,优先处理该方向。
- 状态记录:使用哈希表记录已访问的坐标及对应的最小跳跃次数,避免重复访问。
- 双向搜索终止条件:当两个搜索队列中存在相同坐标时,合并路径长度得到结果。
三、代码实现
python
from collections import deque
def shortest_jump_path(grid):
n, m = len(grid), len(grid[0])
if n == 1 and m == 1:
return 0
# 双向BFS初始化
start_queue = deque()
start_queue.append((0, 0))
start_visited = {(0, 0): 0}
end_queue = deque()
end_queue.append((n-1, m-1))
end_visited = {(n-1, m-1): 0}
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
while start_queue and end_queue:
# 处理起点方向的BFS
for _ in range(len(start_queue)):
x, y = start_queue.popleft()
current_steps = start_visited[(x, y)]
# 检查是否与终点方向相遇
if (x, y) in end_visited:
return current_steps + end_visited[(x, y)]
max_reach = grid[x][y]
for dx, dy in directions:
for step in range(1, max_reach + 1):
nx, ny = x + dx * step, y + dy * step
if 0 <= nx < n and 0 <= ny < m:
if (nx, ny) not in start_visited or current_steps + 1 < start_visited[(nx, ny)]:
start_visited[(nx, ny)] = current_steps + 1
start_queue.append((nx, ny))
# 处理终点方向的BFS
for _ in range(len(end_queue)):
x, y = end_queue.popleft()
current_steps = end_visited[(x, y)]
if (x, y) in start_visited:
return current_steps + start_visited[(x, y)]
max_reach = grid[x][y]
for dx, dy in directions:
for step in range(1, max_reach + 1):
nx, ny = x + dx * step, y + dy * step
if 0 <= nx < n and 0 <= ny < m:
if (nx, ny) not in end_visited or current_steps + 1 < end_visited[(nx, ny)]:
end_visited[(nx, ny)] = current_steps + 1
end_queue.append((nx, ny))
return -1
# 示例测试
grid = [
[2, 1, 1],
[1, 1, 1],
[1, 1, 1]
]
print(shortest_jump_path(grid)) # 输出: 2
四、算法优化与复杂度分析
- 时间复杂度:双向 BFS 将搜索空间从
O(nm)
降低至O(√(nm))
,结合贪心剪枝进一步减少无效搜索。 - 空间复杂度:使用哈希表记录访问状态,空间复杂度为
O(nm)
,但实际运行中因剪枝策略空间占用显著降低。
五、扩展思考
本题可进一步扩展为三维网格或动态变化的跳跃规则,例如:
- 网格中某些单元格的跳跃步数随时间变化。
- 增加跳跃方向的限制(如只能向对角线方向跳跃)。
- 引入权重机制,不同路径消耗不同能量,需在最短路径与能量消耗间权衡。