给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例 1:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: [2,3,0,1,4]
输出: 2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
====友情提示:本文非最优解。但是更通用====
思路:
=======解法1 带记忆的递归=======
1.构造递归函数,表示还剩多少步到数组尾部。然后就可以直接写了
class Solution {
public int jump(int[] nums) {
//带个缓存,避免重复计算
int[] cache = new int[nums.length];
return dfs(0,nums,cache);
}
/**
* 当前还需要多少步到结尾
* @param curIndex nums当前坐标
* @param nums
* @param cache 带个缓存,避免重复计算
* @return
*/
private int dfs(int curIndex,int[] nums,int[] cache) {
if(curIndex >= nums.length-1) {
return 0;
}
if(cache[curIndex] != 0) {
return cache[curIndex];
}
// 最多可以走多少步
int maxStep = nums[curIndex];
if(maxStep == 0) {
// 一开始没注意题目给的最大值
return Integer.MAX_VALUE - 100;
}
int minStep = Integer.MAX_VALUE;
// 保证当前结果 局部最优解
for(int i=0;i<maxStep;i++) {
// 试探出当前最少还需要多少步能到数组末尾
int dfs = dfs(curIndex + i + 1, nums, cache);
// 取最小的
minStep = Math.min(minStep,dfs);
}
cache[curIndex] = minStep + 1;
return minStep + 1;
}
}
=========解法2 动态规划==========
我们说有暴力搜索的地方就有动态规划
所以构造数组dp[i]表示nums的坐标为i时,至少需要多少步到nums末尾。(其实跟上个解法一样)
状态转移方程如下:
然后赋初值就行了,显然应该从尾往头赋值
代码如下:
class Solution {
public int jump(int[] nums) {
// dp[i] 还需要多少步到结尾
int[] dp = new int[nums.length];
// 赋初值
for(int i=0;i<nums.length;i++) {
if(nums[i] == 0) {
dp[i] = 100001;
continue;
}
if(i == nums.length-1) {
dp[i] = 0;
continue;
}
if(i + nums[i] >= nums.length -1 ){
dp[i] = 1;
continue;
}
// 代表未初始化
dp[i] = -1;
}
// 填格子
for(int i=nums.length-1; i>=0; i--) {
if(dp[i] != -1) {
//已赋过初值了
continue;
}
int maxStep = nums[i];
int minRes = 100001;
for(int j = i+1;j<=i+maxStep;j++) {
minRes = Math.min(minRes,dp[j]);
}
dp[i] = minRes + 1;
}
if(dp[0] == 100001){
return 0;
}
return dp[0];
}
}