跳跃游戏 IV 图解题解
这道题到底在问什么
- 输入
- arr=[100,-23,-23,404,100,23,23,23,3,404]
- 输出
- 3(0→4 同值跳,4→3 相邻,3→9 同值跳)
- 输入
- arr=[7]
- 输出
- 0(已经在终点)
最优解:一步一步想明白
- 3记住「值分组、分层 BFS、组用一次就清空」,下面逐帧套它。
- 4先扫一遍数组,把相同值的下标归成组(右侧表)。比如值 100 在下标 [0,4],值 404 在 [3,9]——这两组就是后面「同值瞬移」的跳板。目标:从下标 0 走到下标 9(值 404)。
- 5为什么同值跳厉害?像值 100 的 [0,4]:站在 0 可以一步直接跳到 4,跨过中间一大段。这就是本题能比逐格走快很多的原因。下面开始 BFS。
- 6把起点下标 0(紫)标记已访问、放进队列,当前步数 0。开始一圈圈往外扩。
- 7弹出下标 0(紫),值 100。先看同值组:把组里还没访问的下标 4(绿)入队,然后立刻清空值 100 这一组(右侧变「已清空」)——它们彼此一步可达,留着只会重复。
- 8再看下标 0 的相邻 -1 和 1:把界内、没访问过的 1(绿)入队。另一个相邻 -1(越界),跳过。
- 9这一圈所有下标都展开完了,往外推进一圈,步数 +1 = 1。下一圈要处理的是 [4, 1]。
- 10弹出下标 4(紫),值 100 的同值组之前已经被清空了(右侧),没有新下标可跳,直接看相邻。
- 11再看下标 4 的相邻 3 和 5:把界内、没访问过的 3、5(绿)入队。
- 12弹出下标 1(紫),值 -23。先看同值组:把组里还没访问的下标 2(绿)入队,然后立刻清空值 -23 这一组(右侧变「已清空」)——它们彼此一步可达,留着只会重复。
- 13再看下标 1 的相邻:0(已访问)、2(已访问),没有可入队的新下标。
- 14这一圈所有下标都展开完了,往外推进一圈,步数 +1 = 2。下一圈要处理的是 [3, 5, 2]。
- 15弹出下标 3(紫),值 404。先看同值组:把组里还没访问的下标 9(绿)入队,然后立刻清空值 404 这一组(右侧变「已清空」)——它们彼此一步可达,留着只会重复。
- 16再看下标 3 的相邻:2(已访问)、4(已访问),没有可入队的新下标。
- 17弹出下标 5(紫),值 23。先看同值组:把组里还没访问的下标 6、7(绿)入队,然后立刻清空值 23 这一组(右侧变「已清空」)——它们彼此一步可达,留着只会重复。
- 18再看下标 5 的相邻:4(已访问)、6(已访问),没有可入队的新下标。
- 19弹出下标 2(紫),值 -23 的同值组之前已经被清空了(右侧),没有新下标可跳,直接看相邻。
- 20再看下标 2 的相邻:1(已访问)、3(已访问),没有可入队的新下标。
- 21这一圈所有下标都展开完了,往外推进一圈,步数 +1 = 3。下一圈要处理的是 [9, 6, 7]。
- 22弹出下标 9(绿),它正是最后一个下标 n−1 —— 第 3 圈碰到终点,答案就是 3 步。
- 23回放这条最短路:下标 0 同值跳到 4(都是 100),4 相邻走到 3,3 同值跳到 9(都是 404),正好 3 步到终点。正因为同值组提供了「传送门」,才比一格格挪快得多。
⚠️ 容易写错的地方
✗ 错:同值组用完不清空
✓ 对:展开一个下标后清空它所在值的组
一个值若有 m 个下标,不清空会让这 m 个下标两两互相展开,退化成 O(n²) 甚至超时
✗ 错:改用 DFS 或贪心,一头扎进同值跳就往下走
✓ 对:用 BFS 按距离扩散(分层、或给每个点记 dist 都对)
DFS/贪心不保证先到终点的就是最短;只要按距离一圈圈扩散——无论分层计数还是给每点记 dist——首次到终点即最短
✗ 错:忘了相邻的 i−1 / i+1 也是合法移动
✓ 对:邻居 = 同值组 + 左右相邻
只考虑同值跳会漏掉普通走步,可能到不了或多算
完整代码(Python / C++ / Java)
Python
from typing import List
from collections import defaultdict, deque
class Solution:
def minJumps(self, arr: List[int]) -> int:
n = len(arr)
pos = defaultdict(list)
for i, x in enumerate(arr):
pos[x].append(i)
q = deque([0])
seen = [False] * n
seen[0] = True
steps = 0
while q:
for _ in range(len(q)):
i = q.popleft()
if i == n - 1:
return steps
for j in pos[arr[i]] + [i - 1, i + 1]:
if 0 <= j < n and not seen[j]:
seen[j] = True
q.append(j)
pos[arr[i]].clear()
steps += 1
return -1C++
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
int minJumps(vector<int>& arr) {
int n = arr.size();
unordered_map<int, vector<int>> pos;
for (int i = 0; i < n; ++i) pos[arr[i]].push_back(i);
vector<int> seen(n);
queue<int> q;
q.push(0); seen[0] = 1;
for (int steps = 0; !q.empty(); ++steps) {
for (int sz = q.size(); sz--; ) {
int i = q.front(); q.pop();
if (i == n - 1) return steps;
vector<int> next = pos[arr[i]];
next.push_back(i - 1); next.push_back(i + 1);
for (int j : next) if (j >= 0 && j < n && !seen[j]) {
seen[j] = 1; q.push(j);
}
pos[arr[i]].clear();
}
}
return -1;
}
};Java
import java.util.*;
class Solution {
public int minJumps(int[] arr) {
int n = arr.length;
Map<Integer, List<Integer>> pos = new HashMap<>();
for (int i = 0; i < n; i++) pos.computeIfAbsent(arr[i], k -> new ArrayList<>()).add(i);
boolean[] seen = new boolean[n];
Queue<Integer> q = new ArrayDeque<>();
q.offer(0); seen[0] = true;
for (int steps = 0; !q.isEmpty(); steps++) {
for (int sz = q.size(); sz > 0; sz--) {
int i = q.poll();
if (i == n - 1) return steps;
List<Integer> next = pos.get(arr[i]);
next.add(i - 1); next.add(i + 1);
for (int j : next) if (j >= 0 && j < n && !seen[j]) {
seen[j] = true; q.offer(j);
}
next.clear();
}
}
return -1;
}
}复杂度
时间
O(n)
每个下标入队一次;每个值的组只被展开一次(用后清空),所有同值边总共只走 O(n) 次
空间
O(n)
值→下标表、seen 数组、队列都是 O(n)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 跳跃游戏 IV 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
能不能用双向 BFS 进一步加速?+
可以。从起点和终点同时向中间扩展,两边相遇时把各自步数相加即为答案。双向 BFS 在「分支因子大、最短路较长」时能把搜索空间从指数级近似开方,本题同值组让分支因子可能很大,双向 BFS 常有明显常数级甚至数量级加速。实现上要交替扩展较小的一侧、注意相遇判定。
如果还允许「跳到 arr[j] = arr[i] + k」这类更复杂的边呢?+
思路不变,仍是无权图最短路用 BFS;区别只是「邻居怎么生成」。把生成邻居的规则换掉即可,但要小心新规则会不会让边数爆炸——必要时同样用「分组、用后清理」之类的手段控制同类边只展开一次。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 跳跃游戏 IV 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。