跳跃游戏

原文链接: https://leetcode-cn.com/problems/jump-game/solution/tiao-yue-you-xi-by-leetcode/

跳跃游戏

题目:

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个位置。

示例 1:

输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例 2:

输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。

回溯

这是一个低效的解决方法。我们模拟从第一个位置跳到最后位置的所有方案。从第一个位置开始,模拟所有可以跳到的位置,然后从当前位置重复上述操作,当没有办法继续跳的时候,就回溯。
该方法实测超出时间限制。

public class Solution {
    public boolean canJumpFromPosition(int position, int[] nums) {
        if (position == nums.length - 1) {
            return true;
        }

        int furthestJump = Math.min(position + nums[position], nums.length - 1);
        for (int nextPosition = position + 1; nextPosition <= furthestJump; nextPosition++) 		    {
            if (canJumpFromPosition(nextPosition, nums)) {
                return true;
            }
        }

        return false;
    }

    public boolean canJump(int[] nums) {
        return canJumpFromPosition(0, nums);
    }
}
优化回溯

对于数组中的每个位置,我们记录当前坐标是好 / 坏,记录在数组 memo 中,定义元素取值为 GOOD ,BAD,UNKNOWN。
步骤:
1.初始化 memo 的所有元素为 UNKNOWN,除了最后一个显然是 GOOD (自己一定可以跳到自己)。
2.优化递归算法,每步回溯前先检查这个位置是否计算过(当前值为:GOOD / BAD)
如果已知直接返回结果 True / False
否则按照之前的回溯步骤计算
3.计算完毕后,将结果存入memo表中

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);
    }
}
自底向上的动态规划

这是由于我们每次只会向右跳动,意味着如果我们从右边开始动态规划,每次查询右边节点的信息,都是已经计算过了的,不再需要额外的递归开销,因为我们每次在 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;
    }
}
贪心
class Solution {
public:
    bool canJump(vector& nums) {
        int lastpos = nums.size()-1;
        for(int i=nums.size()-1; i>=0; i--)
        {
            if(i+nums[i]>=lastpos)
            {
                lastpos = i;
            }
        }
        return lastpos == 0;
    }
};

你可能感兴趣的:(跳跃游戏)