【每日算法Day 78】面試經典題:能說出全部四種方法,不錄用你都不可能!

題目鏈接

LeetCode 55. 跳躍遊戲[1]

題目描述

給定一個非負整數數組,你最初位於數組的第一個位置。

數組中的每個元素代表你在該位置可以跳躍的最大長度。

判斷你是否能夠到達最後一個位置。

示例1

        輸入:
[2,3,1,1,4]
輸出:
true
解釋:
我們可以先跳 1 步,從位置 0 到達 位置 1, 然後再從位置 1 跳 3 步到達最後一個位置。

      

示例2

        輸入:
[3,2,1,0,4]
輸出:
false
解釋:
無論怎樣,你總會到達索引爲 3 的位置。但該位置的最大跳躍長度是 0 , 所以你永遠不可能到達最後一個位置。

      

題解

動態規劃+正推

dp[i] 表示位置 i 是否可達,初始的時候都是 0 ,只有 dp[0] = 1 ,因爲起點一定是可達的。

然後從位置 0 開始遍歷。對於位置 i ,如果發現 dp[i] = 0,那麼從前面的位置無法到達它,那麼就更無法到達後面的位置了,所以直接返回 false

否則的話,它能到達的範圍是 i+1i+nums[i] ,所以把這部分的 dp 值都標記爲 1

如果發現 i+nums[i] \ge n-1 ,就說明當前位置直接就能跳到終點了,直接返回 true

時間複雜度 O(n^2),空間複雜度 O(n)

動態規劃+倒推

dp[i] 表示從位置 i 能否到達終點,初始的時候都是 0 ,只有 dp[n-1] = 1 ,因爲從終點一定是可到達終點的。

然後從位置 n-2 開始往前遍歷。對於位置 i ,如果 i+nums[i] \ge n-1,那就說明當前位置直接就可以到達終點,那麼就令 dp[i] = 1

否則的話遍歷所有的 dp[i+1]dp[i+nums[i]] ,如果其中有等於 1 的,那就說明先跳到那個位置,就能再跳到終點了。一個都沒有的話 dp[i] = 0

最後看 dp[0] 是否爲 1 就行了。

時間複雜度 O(n^2),空間複雜度 O(n)

貪心+正推

在上面的動態規劃方法中,對於位置 i ,我們需要把他能到達的位置全部做上標記。

但是其實沒有必要這麼做,只需要記錄一下能到的最遠的那個位置 maxx 就行了。如果遍歷之後的位置 j 時,發現 maxx < j ,那就說明之前的所有位置最遠都無法到達 j ,那就直接返回 false 。否則的話,比較一下當前能到達的最遠位置,更新一下 maxx 的值。

時間複雜度 O(n),空間複雜度 O(1)

貪心+倒推

還是從上面的動態規劃方法改變來的,上面動態規劃在位置 i ,需要遍歷所有它能到達的位置,然後看有沒有位置能夠到達終點。

其實只需要看能到的最遠的那個位置就行了,我們用 minn 表示後面的位置中最靠前的那個能夠到達終點的位置。如果最遠到達位置滿足 i+nums[i] \ge minn,那就說明位置 i 可以直接跳到 minn ,那麼就更新 minn = i 。否則的話怎麼跳都跳不到終點,因爲 iminn 之間的位置都是無法到達終點的。

需要注意的是,這裏最遠的位置 i+nums[i] 不一定能到達終點哦,但是中間的某個位置可能能夠達到。

時間複雜度 O(n),空間複雜度 O(1)

代碼

動態規劃+正推(c++)

        class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n, 0);
        dp[0] = 1;
        for (int i = 0; i < n; ++i) {
            if (!dp[i]) return false;
            if (i+nums[i] >= n-1) return true;
            for (int j = i+1; j <= i+nums[i]; ++j) {
                dp[j] = 1;
            }
        }
        return false;
    }
};

      

動態規劃+倒推(c++)

        class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n, 0);
        dp[n-1] = 1;
        for (int i = n-2; i >= 0; --i) {
            if (i+nums[i] >= n-1) {
                dp[i] = 1;
                continue;
            }
            for (int j = i+1; j <= i+nums[i]; ++j) {
                dp[i] |= dp[j];
                if (dp[i]) break;
            }
        }
        return dp[0];
    }
};

      

貪心+正推(c++)

        class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size(), maxx = 0;
        for (int i = 0; i < n; ++i) {
            if (i > maxx) return false;
            maxx = max(maxx, i+nums[i]);
        }
        return maxx >= n-1;
    }
};

      

貪心+倒推(c++)

        class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size(), minn = n-1;
        for (int i = n-2; i >= 0; --i) {
            if (i+nums[i] >= minn) minn = i;
        }
        return !minn;
    }
};

      

參考資料

[1]

LeetCode 55. 跳躍遊戲: leetcode-cn.com/problem

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章