贪心算法从 0 开始 —— 第 3 章:跳跃游戏 Jump Game
作者:就是滴九点半
标签:算法 / 贪心 / JavaScript / 数组 / 跳跃游戏
✨ 前言
在前两章中,我们学习了两个非常经典的贪心问题 —— 最小货币找零和区间调度,理解了贪心算法的核心思想:每一步都做“当前看起来最优”的选择。
这章我们将挑战一个稍微进阶的问题:跳跃游戏(Jump Game),它不仅在 LeetCode 非常经典,也常出现在笔试、面试中。它是数组类型贪心题的入门门槛。
📌 问题描述(LeetCode 55)
给定一个非负整数数组 nums
,其中每个元素表示你在该位置上最多能跳跃的步数。
问:你是否能够从数组的第一个位置跳到最后一个位置?
示例:
输入: [2, 3, 1, 1, 4]
输出: true
解释: 可以先跳1步到3,再跳3步直接到最后。
输入: [3, 2, 1, 0, 4]
输出: false
解释: 无论怎么跳,都无法越过第3个位置的0。
❌ 暴力法详解:回溯搜索(DFS)
🧠 思路:
- 从起点
0
开始,尝试跳1 ~ nums[0]
步 - 然后对每个跳到的新位置递归尝试跳法
- 只要有一条路径能跳到终点,返回 true,否则 false
✅ JavaScript 实现(暴力递归)
function canJump(nums) {
function dfs(pos) {
if (pos >= nums.length - 1) return true;
let maxStep = nums[pos];
for (let step = 1; step <= maxStep; step++) {
if (dfs(pos + step)) return true;
}
return false;
}
return dfs(0);
}
⛔ 缺点分析
- 每个位置都尝试所有跳法
- 会重复进入同一个位置
- 没有剪枝,时间复杂度约为
O(2^n)
- 大数组会超时(LeetCode 直接 TLE)
✅ 贪心算法详解:一步步跳最远
💡 贪心思想引入:
跳跃游戏本质是:你只关心是否能从起点跳到终点,而不是怎么跳得最优。
于是你只需要记录一个变量 maxReach
,表示你当前能跳到的最远位置,然后遍历数组。
贪心策略:
在遍历每个位置时,都更新“你能跳的最远距离”,如果中间某个点连自己都跳不到(即当前
i > maxReach
),就直接失败。
✅ JavaScript 实现(一步到位)
function canJump(nums) {
let maxReach = 0;
for (let i = 0; i < nums.length; i++) {
if (i > maxReach) return false; // 说明跳不到当前位置
maxReach = Math.max(maxReach, i + nums[i]);
}
return true;
}
🧠 步骤拆解与变量追踪(例子 1)
输入:[2, 3, 1, 1, 4]
目标:判断能否从 0 跳到最后一个位置
位置 i | nums[i] | i + nums[i] | maxReach 更新前 | 更新后 | 能跳过去吗 |
---|---|---|---|---|---|
0 | 2 | 2 | 0 | 2 | ✅ |
1 | 3 | 4 | 2 | 4 | ✅ |
2 | 1 | 3 | 4 | 4 | ✅ |
3 | 1 | 4 | 4 | 4 | ✅ |
4 | 4 | 8 | 4 | 8 | ✅ ✅ 到终点 |
最终 maxReach = 8 ≥ 最后位置 4,可以跳到。
🧊 再看一个失败的例子:[3, 2, 1, 0, 4]
位置 i | nums[i] | i + nums[i] | maxReach 更新前 | 更新后 | 能跳过去吗 |
---|---|---|---|---|---|
0 | 3 | 3 | 0 | 3 | ✅ |
1 | 2 | 3 | 3 | 3 | ✅ |
2 | 1 | 3 | 3 | 3 | ✅ |
3 | 0 | 3 | 3 | 3 | ✅ |
4 | 4 | 8 | 3 | ❌ 无法访问 i=4,跳不到 |
最终无法访问 i=4
,直接返回 false
📚 画图理解(贪心 vs 暴力)
暴力:每个位置都向下分叉,尝试所有可能路径(爆炸级)
贪心:一直往最远能跳的地方推进,不考虑路径,只考虑“能不能活下来”
贪心不是找“路径”,它只管“可达性”。
📈 时间与空间复杂度分析
项目 | 复杂度 |
---|---|
时间 | O(n) (遍历数组一次) |
空间 | O(1) (只用一个变量 maxReach) |
✅ 方法对比总结
方法 | 可行性 | 时间复杂度 | 实现难度 | 是否推荐 |
---|---|---|---|---|
暴力回溯 | ✅ | ❌ O(2^n) | ⭐⭐ | ❌ |
贪心算法 | ✅ | ✅ O(n) | ⭐ | ✅ 强烈推荐 |
✅ 小结(知识点归纳)
核心问题 | 跳跃可达性判定 |
---|---|
贪心思路 | 每步更新“最远可达位置” |
临界判断 | 若当前 i > maxReach,则无法跳过去 |
适用特性 | 单向数组、范围型推进、不关心路径 |
📚 下一章预告:加油站补给(LeetCode 134)
给定一个环形加油站数组,每个加油站给你一定汽油,油耗能让你走到下一个。问是否存在一个起点可以绕一圈。
这是贪心处理“环形结构”的经典题,难度更进一步,我们将在下一章深入分析。
如果你觉得这个系列对你有帮助,欢迎点赞、收藏、评论!
我是就是滴九点半,我们下一章继续进击贪心算法!
—— END ——