美文网首页
LeetCode 力扣 55. 跳跃游戏

LeetCode 力扣 55. 跳跃游戏

作者: windliang | 来源:发表于2020-02-02 10:30 被阅读0次

    题目描述(中等难度)

    45题的时候已经见过这道题了,只不过之前是返回从第 0 个位置能跳到最后一个位置的最小步数,这道题是返回是否能跳过去。

    leetCode Solution 中给出的是动态规划的解法,进行了一步一步的优化,但都也比较慢。不过,思路还是值得参考的,上边说的比较详细,这里就不啰嗦了。这里,由于受到 45 题的影响,自己对 45 题的解法改写了一下,从而解决了这个问题。

    下边的解法都是基于45题 的想法,大家可以先过去看一下,懂了之后再回到下边来看。

    解法一 顺藤摸瓜

    45 题的代码。

    public int jump(int[] nums) {
        int end = 0;
        int maxPosition = 0; 
        int steps = 0;
        for(int i = 0; i < nums.length - 1; i++){
            //找能跳的最远的
            maxPosition = Math.max(maxPosition, nums[i] + i); 
            if( i == end){ //遇到边界,就更新边界,并且步数加一
                end = maxPosition;
                steps++;
            }
        }
        return steps;
    }
    

    这里的话,我们完全可以把 step 去掉,并且考虑下当前更新的 i 是不是已经超过了边界。

    public boolean canJump(int[] nums) { 
        int end = 0;
        int maxPosition = 0;  
        for(int i = 0; i < nums.length - 1; i++){
            //当前更新超过了边界,那么意味着出现了 0 ,直接返回 false
            if(end < i){
                return false;
            }
            //找能跳的最远的 
            maxPosition = Math.max(maxPosition, nums[i] + i); 
           
            if( i == end){ //遇到边界,就更新边界,并且步数加一
                end = maxPosition; 
            }
        }
        //最远的距离是否到答末尾
        return maxPosition>=nums.length-1;
    }   
    

    时间复杂度:O(n)。

    空间复杂度:O(1)。

    解法二 顺瓜摸藤

    每次找最左边的能跳到当前位置的下标,之前的代码如下。

    public int jump(int[] nums) {
        int position = nums.length - 1; //要找的位置
        int steps = 0;
        while (position != 0) { //是否到了第 0 个位置
            for (int i = 0; i < position; i++) {
                if (nums[i] >= position - i) {
                    position = i; //更新要找的位置
                    steps++;
                    break;
                }
            }
        }
        return steps;
    }
    
    

    这里修改的话,只需要判断最后回没回到 0 ,并且如果 while 里的 for 循环没有进入 if ,就意味着一个位置都没找到,就要返回 false。

    public boolean canJump(int[] nums) { 
        int position = nums.length - 1; //要找的位置
        boolean isUpdate = false; 
        while (position != 0) { //是否到了第 0 个位置
            isUpdate = false;
            for (int i = 0; i < position; i++) {
                if (nums[i] >= position - i) {
                    position = i; //更新要找的位置 
                    isUpdate = true;
                    break;
                }
            }
            //如果没有进入 for 循环中的 if 语句,就返回 false
            if(!isUpdate){
                return false;
            }
        }
        return true;
    }
    

    时间复杂度:O(n²)。

    空间复杂度:O(1)。

    解法三

    让我们直击问题的本质,与 45 题不同,我们并不需要知道最小的步数,所以我们对跳的过程并不感兴趣。并且如果数组里边没有 0,那么无论怎么跳,一定可以从第 0 个跳到最后一个位置。

    所以我们只需要看 0 的位置,如果有 0 的话,我们只需要看 0 前边的位置,能不能跳过当前的 0 ,如果 0 前边的位置都不能跳过当前 0,那么直接返回 false。如果能的话,就看后边的 0 的情况。

    public boolean canJump(int[] nums) {
        for (int i = 0; i < nums.length - 1; i++) {
            //找到 0 的位置
            if (nums[i] == 0) {
                int j = i - 1;
                boolean isCanSkipZero = false;
                while (j >= 0) {
                    //判断 0 前边的元素能否跳过 0 
                    if (j + nums[j] > i) {
                        isCanSkipZero = true;
                        break;
                    }
                    j--;
                }
                if (!isCanSkipZero) {
                    return false;
                }
            }
        }
        return true;
    }
    

    但这样时间复杂度没有提高, 在 @Zhengwen 的提醒下,可以用下边的方法。

    我们判断 0 前边的元素能否跳过 0 ,不需要每次都向前查找,我们只需要用一个变量保存当前能跳的最远的距离,然后判断最远距离和当前 0 的位置就可以了。

    public boolean canJump(int[] nums) {
        int max = 0;
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] == 0 && i >= max) {
                return false;
            }
            max = Math.max(max, nums[i] + i);
        }
        return true;
    }
    

    时间复杂度:O(n)。

    空间复杂度:O(1)。

    参考这里,我们甚至不需要考虑 0 的位置,只需要判断最大距离有没有超过当前的 i 。

    public boolean canJump(int[] nums) {
        int max = 0; 
        for (int i = 0; i < nums.length; i++) {
            if (i > max) {
                return false;
            }
            max = Math.max(max, nums[i] + i);
        }
        return true;
    }
    

    当自己按照 45 题的思路写完的时候,看 Solution 的时候都懵逼了,这道题竟然这么复杂?不过 Solution 把问题抽象成动态规划的思想,以及优化的过程还是非常值得学习的。

    更多详细通俗题解详见 leetcode.wang

    相关文章

      网友评论

          本文标题:LeetCode 力扣 55. 跳跃游戏

          本文链接:https://www.haomeiwen.com/subject/pjnfxhtx.html