LeetCode 第55题:跳跃游戏
题目描述
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。
难度
中等
题目链接
示例
示例 1:
输入:nums = [2,3,1,1,4] 输出:true 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4] 输出:false 解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示
1 <= nums.length <= 10^40 <= nums[i] <= 10^5
解题思路
贪心算法
这道题可以使用贪心算法,维护一个能到达的最远位置。如果最远位置大于等于最后一个位置,则说明可以到达。
关键点:
- 维护当前能到达的最远位置
- 遍历数组时只需要遍历到当前能到达的最远位置
- 更新最远位置时考虑当前位置能跳的距离
- 如果当前位置已经无法到达,直接返回false
具体步骤:
- 初始化最远可到达位置为0
- 遍历数组,对于每个位置:
- 如果当前位置已经无法到达,返回false
- 更新最远可到达位置
- 判断最远位置是否可以到达最后一个位置
图解思路
算法步骤分析表
| 步骤 | 当前位置 | 当前值 | 最远可达 | 说明 |
|---|---|---|---|---|
| 初始 | 0 | 2 | 2 | 可以跳到索引1或2 |
| 第1步 | 1 | 3 | 4 | 可以跳到索引4 |
| 第2步 | 2 | 1 | 4 | 最远距离不变 |
| 第3步 | 3 | 1 | 4 | 最远距离不变 |
| 第4步 | 4 | 4 | 4 | 已到达终点 |
状态/情况分析表
| 情况 | 输入 | 输出 | 说明 |
|---|---|---|---|
| 单元素 | [0] | true | 已在终点 |
| 可到达 | [2,3,1,1,4] | true | 有效路径 |
| 不可达 | [3,2,1,0,4] | false | 被0阻断 |
代码实现
C# 实现
public class Solution {
public bool CanJump(int[] nums) {
int maxReach = 0;
for (int i = 0; i <= maxReach; i++) {
// 如果已经到达或超过最后一个位置,返回true
if (i >= nums.Length - 1) return true;
// 更新最远可达位置
maxReach = Math.Max(maxReach, i + nums[i]);
// 如果当前位置已是最远可达位置,且无法继续前进
if (i == maxReach && nums[i] == 0) return false;
}
return false;
}
}
执行结果
- 执行用时:108 ms
- 内存消耗:42.5 MB
代码亮点
- 🎯 使用贪心策略优化性能
- 💡 巧妙处理边界情况
- 🔍 提前判断无法到达的情况
- 🎨 代码简洁易懂
常见错误分析
- 🚫 没有考虑数组长度为1的情况
- 🚫 更新最远距离的逻辑错误
- 🚫 遍历范围不正确
- 🚫 提前返回条件判断错误
解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 动态规划 | O(n²) | O(n) | 思路直观 | 效率低 |
| 贪心算法 | O(n) | O(1) | 最优性能 | 不易想到 |
| 回溯法 | O(2ⁿ) | O(n) | 找到所有路径 | 超时 |