文章目录
- 题目链接
- 题目描述
- 代码
- 1.动态规划
- 2.贪心
题目链接
55.跳跃游戏
题目描述
代码
1.动态规划
1.1 dp数组的含义
dp[i]:从[0,i]的任意一点处出发,你最大可以跳跃到的位置。
例如nums=[2,3,1,1,4]中:
dp[0]=2 dp[1]=4 dp[2]=4 dp[3]=4 dp[4]=8(其实我们没有必要去讨论最后一个下标,因为从最后一个下标出发一定可以到最后一个)
1.2 dp数组的递推公式
dp[i]=max(dp[i−1],nums[i]+i)
dp[i] 代表的是从[0,i]的任意一点处出发,你最大可以跳跃到的位置,那么就考虑是否从下标i出发,于是dp[i]可以由两个方面推出:
从下标i出发,能到达的位置是nums[i]+i
不从下标i出发,最大能到达的就是dp[i−1]
所以 dp[i]=max(dp[i−1],nums[i]+i)
由dp[i]的定义可以知道,dp[0]=nums[0]
1.3 怎么判断是不是可以到达最后一位?
从dp[i]的定义我们可以知道,dp[i]的大小一定是单调不减的,因为nums中的元素都是大于等于0的,我们不可能倒着走回来。把我们想象成棋子,当遇到什么情况的时候,棋子将会原地踏步无法向前进呢?其实就是当dp[i]==i的时候。试想,当棋子来到下标i的时候,上帝却告诉它你最多只能到下标i,那棋子不就再也不能向前进了吗?想通了这个代码就呼之欲出了。
public boolean canJump(int[] nums) {
if(nums.length ==1){
return true;
}
if(nums[0] ==0){
return false;
}
int[] dp =new int[nums.length];//从[0,i]的任意一点处出发,你最大可以跳跃到的位置
dp[0] =nums[0];
for(int i=1;i<nums.length;i++){
dp[i] = Math.max(nums[i]+i,dp[i-1]);
if(dp[i] >=nums.length-1){
return true;
}
if(dp[i] ==i){
return false;
}
}
return true;
}
2.贪心
每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。
贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。
i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。
而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。
如果 cover 大于等于了终点下标,直接 return true 就可以了。
public boolean canJump(int[] nums) {
int cover =0;//覆盖的范围
if(nums.length == 1){
return true;
}
for(int i=0;i<=cover;i++){
cover = Math.max(nums[i]+i,cover);
if(cover >= nums.length-1){
return true;
}
}
return false;
}