📝 题目描述

题目链接跳跃游戏

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false

示例:

1
2
3
4
5
6
7
8
9
10
11
示例 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^4
  • 0 <= nums[i] <= 10^5

💡 解题思路

方法一:贪心算法

刚看到本题一开始可能想:当前位置元素如果是 3,我究竟是跳一步呢,还是两步呢,还是三步呢,究竟跳几步才是最优呢?

其实跳几步无所谓,关键在于可跳的覆盖范围!不一定非要明确一次究竟跳几步,每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。这个范围内,别管是怎么跳的,反正一定可以跳过来。那么这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点

这样一来,我们依次遍历数组中的每一个位置,并实时维护 最远可以到达的位置。对于当前遍历到的位置 xx,如果它在 最远可以到达的位置 的范围内,那么我们就可以从起点通过若干次跳跃到达该位置,因此我们可以用 x+nums[x]x+nums[x] 更新 最远可以到达的位置

在遍历的过程中,如果 最远可以到达的位置 大于等于数组中的最后一个位置,那就说明最后一个位置可达,我们就可以直接返回 True 作为答案。反之,如果在遍历结束后,最后一个位置仍然不可达,我们就返回 False 作为答案。

贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围);
整体最优解:最后得到整体最大覆盖范围,看是否能到终点。

🔧 代码实现

1、贪心算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
bool canJump(vector<int>& nums) {
// 初始能覆盖到的下标 = 0
int distance = 0, n = nums.size();
// 不断扩展下标覆盖范围
for (int i = 0; i <= distance; i++) {
// 更新最大覆盖范围
distance = max(i + nums[i], distance);
// 防止越界
if (distance >= n - 1) return true;
}
// 能运行到这里,说明没有覆盖到终点
return false;
}
};

📊 复杂度分析

1、贪心算法

  • 时间复杂度O(n)O(n),其中 n 为数组的大小。只需要访问 nums 数组一遍,共 n 个位置。
  • 空间复杂度O(1)O(1),不需要额外的空间开销。

🎯 总结

  • 核心思想:不断拓宽覆盖范围。