题目
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
思路一 动规(菜鸡的思路)
我们维护一个动规数组dp,大小为nums的长度,初始值均Integer.MAX_VALUE-1,dp[index]代表跳到index的位置需要dp[index]次步数
维护策略如下:
对于每个nums[i],我们更新dp[i+1…i+nums[i]]。
dp[j]=Math.min(dp[j],dp[i]+1)。
最后我们返回dp[nums.length-1]。
但其实这道题正确的思路用的是贪心,动规能做,但复杂度过高,很容易超时。
思路一代码
public class problem45 {
public int jump(int[] nums) {
int[] dp=new int[nums.length];
for(int i=0;i<nums.length;i++){
dp[i]=Integer.MAX_VALUE-1;
}
dp[0]=0;
for(int i=0;i<nums.length-1;i++){
if(nums[i]==0) continue;
for(int j=i+1;j<=nums[i]+i&&j<nums.length;j++){
dp[j]=Math.min(dp[j], dp[i]+1);
}
// for(int k=0;k<dp.length;k++){
// System.out.print(dp[k]+" ");
// }
// System.out.println();
}
return dp[nums.length-1];
}
public static void main(String[] args) {
problem45 pro=new problem45();
int[] nums={2,1};
System.out.println(pro.jump(nums));
}
}
思路二 贪心(大佬的代码)
因为不存在往回走的情况,所以我们每次只需要选择尽可能向前走的走法,那么步数一定会最少。
选择策略如下:
假设现在在索引为i的位置,我们下一步走的就应该是nums[j]+j中较大的那一个,其中i<=j<=i+nums[i];
以下是leetcode大佬解答的部分内容:
LeetCode 讨论里,大部分都是这个思路,贪婪算法,我们每次在可跳范围内选择可以使得跳的更远的位置。
如下图,开始的位置是 2,可跳的范围是橙色的。然后因为 3 可以跳的更远,所以跳到 3 的位置。
如下图,然后现在的位置就是 3 了,能跳的范围是橙色的,然后因为 4 可以跳的更远,所以下次跳到 4 的位置。
写代码的话,我们用 end 表示当前能跳的边界,对于上边第一个图的橙色 1,第二个图中就是橙色的 4,遍历数组的时候,到了边界,我们就重新更新新的边界。
思路二代码
public int jump(int[] nums) {
int end = 0;
int maxPosition = 0;
int steps = 0;
for(int i = 0; i < nums.length - 1; i++){
//找能跳的最远的
maxPosition = Math.max(maxPosition, nums[i] + i);
if( i == end){ //遇到边界,就更新边界,并且步数加一
end = maxPosition;
steps++;
}
}
return steps;
}
此代码作者:windliang
链接:https://leetcode-cn.com/problems/jump-game-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-10/
来源:力扣(LeetCode)
但是,这代码不太好理解,比较巧妙,反正要我自己写一次,估计挺难的。