题目地址
https://leetcode-cn.com/problems/jump-game/
题目描述
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
思路1 - 回溯
回溯就是穷举,有成功的分支即返回true;
这个方法会超时,时间复杂度为 O ( 2 n ) O(2^n) O(2n),空间复杂度 O ( 2 n ) ; O(2^n); O(2n);
代码1
bool cJump(int *nums, int numsSize, int position) {
if(position == numsSize - 1) return true;
//从大往小扫描可以优化成功时的时间
int i = (position + nums[position] < numsSize - 1 ? position + nums[position] : numsSize - 1);
for(;i > position;i--) {
if(cJump(nums, numsSize, i)) return true;
}
return false;
}
bool canJump(int* nums, int numsSize){
return cJump(nums, numsSize, 0);
}
思路2 - 动态规划
dp[i]:位置i是否能到达;
状态转移方程: d p [ i ] = { t r u e ∃ j ∈ [ 0 , i ) 满 足 d p [ j ] = t r u e & & j + n u m s [ j ] > = i f a l s e 其 他 dp[i] = \begin{cases} true & \exist j \in [0, i) 满足dp[j] = true \&\& j + nums[j] >= i \\ false & 其他 \end{cases} dp[i]={truefalse∃j∈[0,i)满足dp[j]=true&&j+nums[j]>=i其他
base case: dp[0] = true;
时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( 1 ) O(1) O(1)
代码2
bool canJump(int* nums, int numsSize){
bool res;
bool *dp = (bool*)malloc(sizeof(bool) * numsSize);
memset(dp, false, numsSize);
dp[0] = true;
for(int i = 1;i < numsSize;i++) {
for(int j = 0;j < i;j++) {
if(dp[j] == true && j + nums[j] >= i) {
dp[i] = true;
break;
}
}
}
res = dp[numsSize-1];
free(res);
return dp[numsSize-1];
}
思路3 - 贪心
维护一个最远可达位置, 对于每一个可到达的位置x,最远可到达的位置是x + nums[x],小于这个数的位置一定可以到达;
从头扫描数组,如果最远可达位置大于等于numsSize-1,则返回true;扫描到最远可达位置时还未包含数组最后一个位置,则返回false;
时间复杂度
O
(
n
)
O(n)
O(n);
空间复杂度
O
(
1
)
O(1)
O(1);
代码3
bool canJump(int* nums, int numsSize){
int maxIndex = 0;
for(int i = 0;i <= maxIndex;i++) {
if(i + nums[i] > maxIndex) {
maxIndex = i + nums[i];
}
if(maxIndex >= numsSize - 1) return true;
}
return false;
}