这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战
题目
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例
输入: nums = [2,3,1,1,4]
输出: true
解释: 可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示
- 1 <= nums.length <= 3 *
- 0 <= nums[i] <=
解题思路
通过题目可以比较直观的看到,元素值nums[i]为当前位置可跳的步数,那么我们可以得出当前位置i的最远可达位置为i + nums[i],由此可得公式为:dp[i] = max(dp[i - 1], i + nums[i])
在套用公式的同时,由于我们是要判断能否跳到数组末尾处,那么在中间如果有缺口的话(dp[i - 1] < i),就需要我们再做一个判断来停止推导,否则会导致最终结果失真。
代码实现
方式一:动态规划
class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
// 初始化
int[] dp = new int[n];
dp[0] = nums[0];
for(int i = 1; i < n; ++i){
// 缺口判断
if(i > dp[i - 1]){
return false;
}
// 状态转移
dp[i] = Math.max(i + nums[i], dp[i - 1]);
}
// 返回结果
return dp[n - 1] >= n - 1;
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
方式二:动态规划优化
在方式一中我们定义了一个数组,但实际上在状态转移的过程中我们只用到了dp[i - 1]这一个值而已,那么我们可以在这进行一个优化。
class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
// 最远边界,相当于dp[i - 1]
int max = nums[0];
for(int i = 1; i < n - 1; ++i){
if(i > max){
return false;
}
// 状态转移
max = Math.max(max, i + nums[i]);
}
// 返回结果
return max >= n - 1;
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
方式三:倒推法
在一个有限的数组中,边界是确定了的,那么我们除了从前往后遍历,还可以从后往前遍历,进行状态的转移。
从末尾idx开始,往前遍历,前面的元素能否跳到idx处,如果可以,更新idx为当前索引i。
class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
int idx = n - 1;
for(int i = n - 2; i >= 0; --i){
// 当前位置可以跳到 idx 处,更新 idx
if(i + nums[i] >= idx){
idx = i;
}
}
// 返回结果
return idx == 0;
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!