题解
LeetCode 上这种题目的变形非常多。因为比较相似这次两题一起写,思路比较连贯一点。
第一题 55. mid 难度。这题只要判断能否到达尾部。我们用一个变量
cur_max记录可到达的最远位置,遍历数组即可。
注意此处出现的span数组,意为在i处时能到达的最远位置,这是此题的关键。
第二题 45. hard。 也不难,算最小步长,但是测试用例里有一个case卡时间。
最小最大,很明显是dp的感觉。
那么我们设 dp[ i ] 为到达 i 位置是所需的最小步长。
我想到了两种状态转移方法。
- dp[ i ] = min { dp[ k ] + 1 | k : span[ k ]>=i } // 后退式
- dp[ i ] = min{ dp [ j ] + 1 | j : i<= j <=span[ i ] } //前进式
本质是一样的,但是循环方式不一样。
还要剪枝,方法就是第一次出现的span[]超过了n就可以结束dp循环了。
Code
bool canJump(vector<int>& nums) {
int n =nums.size();
vector<int> span(n);
for(int i=0;i<n;i++) span[i]=i+nums[i];
int cur_max=0;
for(int i=0;i<n;i++){
if(i<=cur_max && span[i]>cur_max)
cur_max = span[i];
}
return cur_max>=n-1;
}
int jump(vector<int>& nums) {
int n =nums.size();
vector<int> dp(n,99999),span(n);
if(n<2) return 0;
for(int i=0;i<n;i++) span[i]=i+nums[i];
dp[0]=0;
/* 1. method valid but time limit exceeded
if(span[0]>=n-1) return dp[0]+1;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if( span[j]>= i){
dp[i] = min(dp[i],dp[j]+1);
// prune 剪枝
if(span[i]>=n-1) return dp[i]+1;
}
}
}
*/
// 2. method valid
for(int i=0;i<n;i++){
for(int j=i;j<=span[i]&&j<n;j++){// j may exceed the range
dp[j] = min(dp[i]+1,dp[j]);
// prune 剪枝
if(span[j]>=n-1) return dp[j]+1;
}
}
return dp[n-1];
}