[Leetcode]44.跳躍遊戲Ⅰ&&45.跳躍遊戲Ⅱ

AdamWong發表於2019-01-04

跳躍遊戲連結

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

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

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

示例 1:

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

示例 2:

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

思路:

如果只是判斷能否跳到終點,我們只要在遍歷陣列的過程中,更新每個點能跳到最遠的範圍就行了,

如果最後這個範圍大於等於終點,就是可以跳到。

class Solution {
private:
    inline int max(const int a,const int b){return a>b?a:b;}
    
public:
    bool canJump(vector<int>& nums) {
        int count=0;
        for(int i=0;i<nums.size()&&i<=count;i++){
            count=max(count,i+nums[i]);
        }
        if(count<nums.size()-1)return false;
        return true;
    }
};

 

跳躍遊戲Ⅱ
現在來看跳躍問題一的衍生:

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

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

你的目標是使用最少的跳躍次數到達陣列的最後一個位置。

示例:

輸入: [2,3,1,1,4]
輸出: 2
解釋: 跳到最後一個位置的最小跳躍數是 2。
     從下標為 0 跳到下標為 1 的位置,跳 1 步,然後跳 3 步到達陣列的最後一個位置。

說明:

假設你總是可以到達陣列的最後一個位置。

 

第一種方法: 動態規劃(超時)

定義狀態dp[i]:到達位置i的最小步數

初始化dp: 0x3f3f3f3f,即一個極大值。

狀態轉移方程:對每個位置i為起點可以到達的位置j,都有dp[j]=min(dp[i]+1,dp[j]);

最後想要的結果:dp[n-1]

時間複雜度:O(n^2)

class Solution {
private: inline int min(const int a,const int b){return a>b?b:a;}
public:
    int jump(vector<int>& nums) {
        int n=nums.size();
        int dp[n];
        memset(dp,0x3f,sizeof(dp));
        /*初始化成最大值*/
        dp[0]=0;
        for(int i=0;i<n-1;i++){
            for(int j=i+1;j<n&&j<=i+nums[i];j++)
                dp[j]=min(dp[i]+1,dp[j]);
        }
        return dp[n-1];
    }
};

 

 

第二種方法:貪心演算法

我們可以把整個陣列分成很多個區域,

把樣例[2,3,1,1,4]拿來做例子:

[2,3,1,1,4] 可以分成如左邊三個區域,第i個區域代表從起點可以通過i-1步到達這些區域。

如何求上述分成上述區域呢?如下遞迴定義:

第1個區域就是起始位置一個。

第n個區域為(第n-1個區域最遠的位置, 第n-1個區域為起點所到達的最遠位置]

如何求這些區域呢,實際上可以遍歷的過程中動態的求。

我們需要每次遍歷的時候更新這些區域,實際上我們就用了兩個變數currentReach和newReach區分割槽域,

前者記錄現在區域的最遠位置,newReach代表從這個區域能到達的最遠位置。有上面我們可以知道下一個區域的範圍為(currentReach,newReach]

因為我們只考慮最後一個點在第ans個區域而答案就是ans-1。遍歷的過程中如果下標大於currentReach,說明進入了一個新的區域,區域就要更新。

newReach要不斷更新的原因是,在到達currentReach前,我們並不知道從現在區域到達的最遠位置,必須不斷更新尋找。

 

程式碼如下:

 1 class Solution {
 2     inline int max(const int a,const int b){return a>b?a:b;}
 3 public:
 4     int jump(vector<int>& nums) {
 5         int newReach=0;//記錄從現在區域出發能到達的最遠位置
 6         int ans=0;//記錄次數
 7         int currentReach=0;//記錄現在區域的最遠位置
 8         int n=nums.size();
 9         for(int i=0;i<n;i++){
10             if(i>currentReach){//超過現在區域的最遠位置,說明進入了一個新區域,ans++
11                 ans++;
12                 currentReach=newReach;//更新現在區域的最遠位置
13             }
14             newReach=max(newReach,i+nums[i]);//每次都更新從此區域出發的最遠到達位置
15         }
16         return ans;
17     }
18 };

 

相關文章