思路
方法1: canJump01
- 使用递归(回溯法)
这个方法是通过递归实现的,它从数组的第一个位置开始,尝试所有可能的跳跃步数,直到达到数组的最后一个位置或遍历完所有的可能性。
思路:
- 如果数组为空或者长度为0,直接返回
false
。 - 从数组的第一个位置(
index = 0
)开始调用递归函数process
。 - 递归的终止条件是,如果当前的
index
等于N-1
(数组的最后一个位置),则返回true
。 - 在当前位置,根据该位置的数字决定可以跳跃的步数范围,递归地尝试每一种跳跃步数。
- 如果任何一种跳跃方式可以到达最后位置,则返回
true
。
缺点:
- 这种方法的时间复杂度非常高,因为它尝试了所有可能的路径,可能导致指数级的计算量。
方法2: canJump02
- 使用动态规划
这个方法使用了动态规划(DP)来减少重复计算,提高效率。
思路:
- 初始化一个布尔型的数组
dp
,其中dp[i]
表示是否可以从起始位置跳跃到位置i
。 dp[0]
初始化为true
,因为起始位置总是可达的。- 从
i = 1
开始遍历数组,对于每个位置i
,检查所有之前的位置j
,看是否存在一个j
,使得从j
跳跃到i
是可行的(即dp[j]
为true
且j + nums[j]
大于等于i
)。 - 如果找到这样的
j
,则设置dp[i] = true
并中断当前循环。
优点:
- 时间复杂度为 O(n^2),空间复杂度为 O(n)。
方法3: canJump
- 贪心算法
使用贪心算法解决问题,思路更为直接和高效。
思路:
- 维护一个变量
maxReach
来存储从起点开始可达的最远位置。 - 遍历数组,对于每个位置
i
,首先检查i
是否超过了之前的maxReach
。如果超过,则说明无法到达当前位置,返回false
。 - 然后更新
maxReach
为max(maxReach, i + nums[i])
。 - 如果在任何时刻
maxReach
大于等于数组的最后位置,直接返回true
。
优点:
- 时间复杂度为 O(n),空间复杂度为 O(1),是三种方法中最优的。
代码如下:
java
class Solution {
public boolean canJump01(int[] nums) {
if (nums==null||nums.length==0){
return false;
}
return process(nums,0,nums.length);
}
private boolean process(int[] nums, int index, int N) {
if (index==N-1){
return true;
}
int num=nums[index];
boolean ans=false;
//当前节点跳 1-num 步
for (int i = 1; i <=num; i++) {
ans=ans||process(nums,index+i,N);
}
return ans;
}
public boolean canJump02(int[] nums){
if (nums==null||nums.length==0){
return false;
}
int N=nums.length;
boolean[] dp = new boolean[N];
dp[0] = true; // 起点是可达的
for (int i = 1; i < nums.length; i++) {
// 初始化当前位置为不可达
dp[i] = false;
// 遍历到当前位置之前的所有位置
for (int j = 0; j < i; j++) {
// 如果位置 j 可达,并且从 j 跳跃足够远以到达 i
if (dp[j] && j + nums[j] >= i) {
dp[i] = true;
break; // 找到一个可达的位置后,无需继续检查
}
}
}
return dp[N-1];
}
//假设从 0 跳 最远跳到i位置 那说明 0-i都是可达的,所以只需要关心每次跳多远即可
//然后再次从1 位置尝试跳最远 如果1 >max 说明在0位置跳的时候无法跳到1
public boolean canJump(int[] nums) {
int maxReach = 0; // 可达的最远位置
for (int i = 0; i < nums.length; i++) {
// 如果当前位置超过了最远可达位置,则无法继续
if (i > maxReach) {
return false;
}
// 更新最远可达位置
maxReach = Math.max(maxReach, i + nums[i]);
// 如果最远可达位置已经超过或到达数组的最后一个位置
if (maxReach >= nums.length - 1) {
return true;
}
}
// 结束循环后,如果还没返回true,则说明最后位置不可达
return false;
}
}