跳跃游戏:
给你一个非负整数数组 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.初始化两个变量,maxReach 表示当前可以到达的最远下标,初始值为 0,因为最开始你位于第一个下标。初始化另一个指针 i 表示当前考虑的下标,初始值也为 0。 2.遍历数组 nums 从第一个元素开始(下标为 0): (1)如果 i 小于或等于 maxReach,说明当前下标仍然在可到达范围内。 更新 maxReach 为 max(maxReach, i + nums[i]),即当前最远位置与当前下标加上可以跳跃的最大长度中的较大值。 (2)如果 maxRearch 能够到达或超过数组的最后一个下标(nums.length - 1),则返回 true,否则在循环结束后返回 false。
思路模拟:假设我们有数组 nums = [2, 3, 1, 1, 4]
,我们可以这样一步步执行算法:
- 初始状态:最远可达到下标
maxReach = 0
,当前下标= 0
- 考虑第一个元素
nums[0] = 2
:- 因为
0
≤maxReach
,更新maxReach
= max(0
,0 + 2
) = 2 - 此时,
maxReach
为 2,意味着我们可以至少到达下标 2 的位置
- 因为
- 移动到下标 1:
- 因为
1
≤maxReach
,更新maxReach
= max(2
,1 + 3
) = 4 - 此时,
maxReach
为 4,意味着我们可以至少到达下标 4 的位置
- 因为
- 考虑下标 2:
- 因为
2
≤maxReach
,更新maxReach
= max(4
,2 + 1
) = 4(不变)
- 因为
- 考虑下标 3:
- 因为
3
≤maxReach
,更新maxReach
= max(4
,3 + 1
) = 4(不变)
- 因为
- 此时,我们已经考虑了所有元素,
maxReach
能够达到最后一个下标(4),因此返回true。
大家可以按照这样的方式去模拟第二组示例,你可以发现maxReach最多到达下标3,无法到达最后一个下标4。
实现代码:
public boolean canJump(int[] nums) {
int maxReach = 0; // 当前可以到达的最远下标
for (int i = 0; i < nums.length; i++) {
if (i <= maxReach) { // 如果当前下标在可到达范围内
maxReach = Math.max(maxReach, i + nums[i]); // 更新最远下标
}
}
return maxReach >= nums.length - 1; // 如果最远下标能够到达或超过最后一个下标,返回 true
}
这题用到了贪心算法,有兴趣的朋友可以看看买卖股票最佳时机||,此题也是我提供了两个思路,第二个思路也用到了贪心算法,还对其思想、特点、使用场景做了补充。贪心算法是比较常见的算法了,我们只能多写题,去感悟它的独特之处。