在這個算法題中,咱們將看到貪心算法的應用,今天要講的是LeetCode的第55號題目,Jump Game,這個題目是什麼意思呢?算法
給定一個非負數的數組,最初咱們在第一個數字的位置上,數組中的每個數字表示在當前的位置上你最多能夠跳多遠,題目要求咱們肯定可否跳到數組中的最後一個數。數組
好比給定數組[2,3,1,1,4],你的代碼應該返回true,這其中一個可能的跳躍方式是從2跳到3,而後從3跳到4;固然從2開始以一次一步的方式也能夠跳到最後。微信
而給定數組[3,2,1,0,4],那麼你的函數應該返回false,在這種狀況下不管你用什麼方式都不可能從3跳到最後的4。多線程
那麼咱們該怎樣解決這個問題呢?函數
個人思路ui
有的同窗會以爲的這個問題很差解決,緣由就在於給定一個位置,假設這個位置上的數字是6,也就是說從這個位置開始,你能夠選擇跳一步、也能夠是兩部、三步、四步、五步或者六步,有這麼多可能性你該跳多少步呢?url
順着這個思路走下去的話,那麼你只能把每一種可能性都試一遍了,仍是以上圖爲例,從該位置開始有6種可能性,那麼咱們依次遍歷每個種可能的選擇,各類遍歷方式的組合數是很是巨大的,所以這種思路不可行。spa
正着走不通,那麼讓咱們反向思考一下。.net
這個問題的反向思考是基於這樣的一種觀察,也就是,若是數組中有某個位置沒法到達,那麼咱們就沒法跳到最後一個節點,這是顯而易見的,由於若是能跳到最後一個節點的話,那麼咱們必然要通過數組中的全部節點。換句話說就是若是咱們能跳到最後一個節點的話,那麼咱們必然能跳到數組中任意一個節點。線程
有了這樣的分析實際上就很是簡單了,咱們以前在不少個算法題目中都說過,有時解決一個通用的問題比解決一個具體的問題思考起來要簡單,在這裏具體的那個問題就是判斷是否能跳到最後一個節點,而通用的那個問題就是可否跳到數組中任意一個節點,在這裏咱們就來思考在給定條件下可否跳到數組中任意一個節點,若是能夠的話那麼咱們的函數應該返回true,不然返回false。
咱們仍是從最簡單的狀況一步一步來分析。
對於數組[2,3,1,1,4],首先咱們會被放到2這個位置,接下來咱們判斷可否跳到3?
那麼從2可否跳到3呢?答案很簡單,固然是能夠的,爲何呢?由於從2跳到3只須要一步,而第一個位置咱們最遠能夠跳兩步,所以咱們能夠跳到3:
這樣咱們來到了數組中的第二個數,也就是3,接下來就比較有意思了。
此時咱們的任務就是判斷從節點3可否跳到節點1,那麼能夠跳到嗎?
答案是顯而易見的,固然能夠跳到,爲何呢?由於在當前位置上咱們能夠最多跳3步,而從3跳到1只須要一步,那麼若是當前位置上的數不是3而是0呢?
那麼咱們還能跳到1嗎?答案是能夠的,由於雖然咱們不能從0跳到1,可是能夠從2直接跳到1,從這兩種狀況下你能獲得什麼啓示?
以上兩種狀況給個人啓示就是,可否跳到當前位置取決於當前位置以前的全部位置上的步數,有的同窗會說這不是廢話嗎,是的,這是一句廢話,這句廢話會引導咱們進一步思考,那就是這究竟是怎麼的取決呢?
讓咱們再次回到數組[2,3,1,1,4]的例子,從2能夠跳到1,從3也能夠跳到1,可是2最多能夠跳到1,超出0步,而3最多能夠跳到4,超過了1這個位置兩步,如圖所示:
那麼這張圖告訴咱們什麼呢?是什麼樣的條件決定了能不能跳到當前位置呢?
若是咱們可以保證從在此位置以前任意一個位置(前提是咱們能夠從數組開頭跳到這些位置)起跳能跳到或跳過當前位置,那麼咱們就能夠肯定能夠從數組開頭跳到當前位置。
所以咱們須要記下在該位置以前的全部位置起跳能超過當前位置的最大步數,只要這個最大步數通過每個位置時都大於0,那麼咱們就能肯定必定能夠從開頭跳到最後。而這本質上就是貪心算法,貪心算法的思想是咱們老是在當前就作出最好的選擇,而不是從總體上加以考慮。
上述結論比較拗口,舉個例子你就明白啦,咱們仍是以[2,3,1,1,4]爲例來講明。
最開始咱們在位置2上,此時咱們能夠認爲從位置2起跳能夠超過當前位置2步,所以最大步數是2,咱們將這個最大步數記爲max_step,也就是能超過當前位置的最大步數,咱們的任務就是要保證在每一個位置max_step都要大於0,這樣咱們就必定能到達最後,如圖所示:
接下來是位置3,此時咱們須要將max_step減1,此時max_step爲1是大於0的,由於咱們向前走了一步。咱們能夠選出從3開始起跳,從而能超過3這個位置3步,也能夠選擇使用max_step的起跳位置,也就是2,所以這個最大步數就是max_step = max(3, max_step-1),這時max_step就是3。
接下來是位置1,一樣將max_step減1,此時max_step爲2是大於0的,在這裏咱們能夠選擇從1這個位置起跳,也能夠選擇使用max_step的起跳位置,也就是位置3,這樣咱們又獲得了能新的max_step,即max_step = max(1, max_step-1)。
重複上述過程直到數組最後,若是中途發現max_step已經等於0了,那麼說明咱們沒法從數組開頭跳到最後。
基於上述分析,代碼就很簡單了。
代碼實現
bool canJump(vector<int>& nums) { int len = nums.size(); if(len == 0 || len == 1) return true; int step=nums[0]; for(int i=0;i<len-1;i++){ step = max(step-1,nums[i]); if(step<=0) return false; } return true; }
怎麼樣,有了仔細的分析,代碼是否是不要太簡單?
總結
在本文中咱們首次見到了貪心算法,貪心算法在每次作決策時老是選擇在當前看來最好的那個,值得注意的是,不是全部問題都適用於貪心算法,那麼什麼樣的問題才適用此算法呢,如今就去講解該理論的話可能理解不會那麼深入,在後續文章中咱們還會遇到該算法,見得多了你天然就會明白什麼樣的問題能夠用貪心算法,到那時咱們再來詳解講解該理論。
本文分享自微信公衆號 - 碼農的荒島求生(escape-it)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。