55. 跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
// 我的贪心
class Solution {
public boolean canJump(int[] nums) {
if (nums == null || nums.length == 0 || nums.length == 1) {
return true;
}
boolean res = false;
int position = 0;
while(true) {
int max = position;
for (int i = position + 1;i <= position + nums[position];i++) {
if (i + nums[i] >= nums.length - 1){
max = nums.length - 1;
break;
}
if (i + nums[i] >= max + nums[max]) {
max = i;
}
}
if (max >= nums.length - 1){
res = true;
break;
}
if (max == position){
break;
}
position = max;
}
return res;
}
}
// 官方的贪心
public class Solution {
public boolean canJump(int[] nums) {
int lastPos = nums.length - 1;
for (int i = nums.length - 1; i >= 0; i--) {
if (i + nums[i] >= lastPos) {
lastPos = i;// 更新解目标
}
}
return lastPos == 0;
}
}
// 作者:LeetCode
// 链接:https://leetcode-cn.com/problems/jump-game/solution/tiao-yue-you-xi-by-leetcode/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划
- 自顶向下
enum Index {
GOOD, BAD, UNKNOWN
}
public class Solution {
Index[] memo;
public boolean canJumpFromPosition(int position, int[] nums) {
if (memo[position] != Index.UNKNOWN) {
return memo[position] == Index.GOOD ? true : false;
}
int furthestJump = Math.min(position + nums[position], nums.length - 1);
for (int nextPosition = position + 1; nextPosition <= furthestJump; nextPosition++) {
if (canJumpFromPosition(nextPosition, nums)) {
memo[position] = Index.GOOD;
return true;
}
}
memo[position] = Index.BAD;
return false;
}
public boolean canJump(int[] nums) {
memo = new Index[nums.length];
for (int i = 0; i < memo.length; i++) {
memo[i] = Index.UNKNOWN;
}
memo[memo.length - 1] = Index.GOOD;
return canJumpFromPosition(0, nums);
}
}
// <!--
// 作者:LeetCode
// 链接:https://leetcode-cn.com/problems/jump-game/solution/tiao-yue-you-xi-by-leetcode/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -->
- 自底向上
自底向上和自顶向下动态规划的区别就是消除了回溯,在实际使用中,自底向下的方法有更好的时间效率因为我们不再需要栈空间,可以节省很多缓存开销。更重要的事,这可以让之后更有优化的空间。回溯通常是通过反转动态规划的步骤来实现的。
这是由于我们每次只会向右跳动,意味着如果我们从右边开始动态规划,每次查询右边节点的信息,都是已经计算过了的,不再需要额外的递归开销,因为我们每次在 memo 表中都可以找到结果。
enum Index {
GOOD, BAD, UNKNOWN
}
public class Solution {
public boolean canJump(int[] nums) {
Index[] memo = new Index[nums.length];
for (int i = 0; i < memo.length; i++) {
memo[i] = Index.UNKNOWN;
}
memo[memo.length - 1] = Index.GOOD;
for (int i = nums.length - 2; i >= 0; i--) {
int furthestJump = Math.min(i + nums[i], nums.length - 1);
for (int j = i + 1; j <= furthestJump; j++) {
if (memo[j] == Index.GOOD) {
memo[i] = Index.GOOD;
break;
}
}
}
return memo[0] == Index.GOOD;
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com