給定一個非負整數陣列,你最初位於陣列的第一個位置。
陣列中的每個元素代表你在該位置可以跳躍的最大長度。
判斷你是否能夠到達最後一個位置。
示例 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 };