题目描述:
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
来源:力扣(LeetCode)
思路:贪心难想,想到的动态规划时间复杂度高!
1)动态规划:记录到达每个位置的最短跳数;每个位置的计算,返回从头,去查找可以跳到该位置的位置,记录其dp[j] + 1,每次取出最小的!
一个优化:
每次记录之前范围内最优的情况!
从左起,最先找到的能到达的,一定是最优情况?
确实:每个位置都是最优的到达步数,后面一位,要么和前面一样,要么要加1!前面一定是最小的!下次只用从新位置开始查找即可!
int[] dp = new int[nums.length];//记录的是每个位置最小的跳跃步数
int start = 0;
for(int i = 1;i < nums.length;i++){
for(int j = start;j < i;j++){
if(nums[j] + j >= i){
dp[i] = dp[j] + 1;
start = j;
break;
}
}
}
return dp[nums.length - 1];
2)贪心:① //从后往前,每次找最大?
每次都尽可能走最大的,也就是找到下一步可到达的最大位置下标!
将end作为step加不加1的标准!
每走一步,要更新一下活动的范围区间!
将最后走的位置,放在倒数第二个元素位置,判断需不需要再走最后一步!
其实也就是边界的处理!
如果nums长度为1,进不去for;如果长度大于1,进去数组还要走一步!
代码:
1)把自己整笑的动态规划:时间复杂度 n^2,甚至还要大
class Solution {
public int jump(int[] nums) {
int[] dp = new int[nums.length];//记录的是每个位置最小的跳跃步数
dp[0] = 0;
for(int i = 1;i < nums.length;i++){
dp[i] = Integer.MAX_VALUE;
for(int j = 0;j < i;j++){
if(nums[j] + j >= i){
dp[i] = Math.min(dp[i],dp[j] + 1);
}
}
}
return dp[nums.length - 1];
}
}
2)动态规划优化,需要理解
class Solution {
public int jump(int[] nums) {
int[] dp = new int[nums.length];
int bestStartIndex = 0;
for (int i = 1; i < nums.length; ++i) {
while (i > bestStartIndex + nums[bestStartIndex]) {
bestStartIndex ++;
}
dp[i] = dp[bestStartIndex] + 1;
}
return dp[nums.length - 1];
}
}
3)动态规划优化,需要理解
class Solution {
public int jump(int[] nums) {
if(nums.length == 1) return 0;
int[] dp = new int[nums.length];//记录的是每个位置最小的跳跃步数
int[] step = new int[nums.length];//声明一个数组:记录当前跳跃步数,可以到达的最大位置
step[1] = nums[0];//跳一步能到达的最大位置 ,不会有step[0]
dp[0] = 0;
//逻辑还是更新 到达每个位置最小的跳跃步骤
for(int i = 1;i < nums.length;i++){
//如果到上一个位置,跳跃的步数,能够到达的最大位置,还能到 i,dp[i]就不变
if(step[dp[i - 1]] >= i) dp[i] = dp[i - 1];
else{
dp[i] = dp[i - 1] + 1;
}
//挺牛的优化
if(dp[i]+1 < nums.length)//防止溢出
step[dp[i] + 1] = Math.max(step[dp[i] + 1],i + nums[i]);
}
return dp[nums.length - 1];
}
}
作者:188380780
链接:https://leetcode-cn.com/problems/jump-game-ii/solution/tan-xin-shi-yao-de-wo-zhen-de-bu-hui-tan-a-zhi-nen/
来源:力扣(LeetCode)
3)贪心:
class Solution {
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, i + nums[i]);
//如果走到了当前区间的边,就加1,因为还要走下一步
if (i == end) {
//必然走下一步,就要步子加一
//并且更新之后的区间范围!
end = maxPosition;
steps++;
}
}
return steps;
}
}
4)还有反方向的贪心,时间复杂度为 O(N²),可看LeetCode答案