來見識一下貪心算法:Jump Game

2021-02-20 書圈

在這個算法題中,我們將看到貪心算法的應用,今天要講的是LeetCode的第55號題目,Jump Game,這個題目是什麼意思呢?

給定一個非負數的數組,最初我們在第一個數字的位置上,數組中的每一個數字表示在當前的位置上你最多可以跳多遠,題目要求我們確定能否跳到數組中的最後一個數。

比如給定數組[2,3,1,1,4],你的代碼應該返回true,這其中一個可能的跳躍方式是從2跳到3,然後從3跳到4;當然從2開始以一次一步的方式也可以跳到最後。

而給定數組[3,2,1,0,4],那麼你的函數應該返回false,在這種情況下無論你用什麼方式都不可能從3跳到最後的4。

那麼我們該怎樣解決這個問題呢?

有的同學會覺得的這個問題不好解決,原因就在於給定一個位置,假設這個位置上的數字是6,也就是說從這個位置開始,你可以選擇跳一步、也可以是兩部、三步、四步、五步或者六步,有這麼多可能性你該跳多少步呢?

順著這個思路走下去的話,那麼你只能把每一種可能性都試一遍了,還是以上圖為例,從該位置開始有6種可能性,那麼我們依次遍歷每一個種可能的選擇,各種遍歷方式的組合數是非常巨大的,因此這種思路不可行。

正著走不通,那麼讓我們反向思考一下。

這個問題的反向思考是基於這樣的一種觀察,也就是,如果數組中有某個位置無法到達,那麼我們就無法跳到最後一個節點,這是顯而易見的,因為如果能跳到最後一個節點的話,那麼我們必然要經過數組中的所有節點。換句話說就是如果我們能跳到最後一個節點的話,那麼我們必然能跳到數組中任意一個節點。

有了這樣的分析實際上就非常簡單了,我們之前在很多個算法題目中都說過,有時解決一個通用的問題比解決一個具體的問題思考起來要簡單,在這裡具體的那個問題就是判斷是否能跳到最後一個節點,而通用的那個問題就是能否跳到數組中任意一個節點,在這裡我們就來思考在給定條件下能否跳到數組中任意一個節點,如果可以的話那麼我們的函數應該返回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;     }

怎麼樣,有了仔細的分析,代碼是不是不要太簡單?

在本文中我們首次見到了貪心算法,貪心算法在每次做決策時總是選擇在當前看來最好的那個,值得注意的是,不是所有問題都適用於貪心算法,那麼什麼樣的問題才適用此算法呢,現在就去講解該理論的話可能理解不會那麼深刻,在後續文章中我們還會遇到該算法,見得多了你自然就會明白什麼樣的問題可以用貪心算法,到那時我們再來詳解講解該理論。

相關焦點

  • 詳解貪心算法
    也就是說貪心算法並不從整體最優考慮,它所作出的選擇只是在某種意義上的局部最優選擇。當然,希望貪心算法得到的最終結果也是整體最優的。雖然貪心算法不能對所有問題都得到整體最優解,但對許多問題它能產生整體最優解。如單源最短路經問題,最小生成樹問題等。在一些情況下,即使貪心算法不能得到整體最優解,其最終結果卻是最優解的很好近似。
  • 每日一道貪心算法
    (百度百科)貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。
  • (貪心算法系列一)
    ❝通知:很多同學感覺自己基礎還比較薄弱,想循序漸進的從頭學一遍數據結構與算法,那你來對地方了。在公眾號左下角「算法匯總」裡已經按照各個系列難易程度排好順序了,大家跟著文章順序打卡學習就可以了,留言區有很多錄友都在從頭打卡!「算法匯總」會持續更新,大家快去看看吧!
  • 貪心算法:加油站
    可以看一下公眾號左下角的「算法匯總」,「算法匯總」已經把題目順序編排好了,文章順序即刷題順序,這是全網最詳細的刷題順序了,方便錄友們從頭打卡學習,「算法匯總」會持續更新!❞134.貪心算法(方法一)直接從全局進行貪心選擇,情況如下:情況一:如果gas的總和小於cost總和,那麼無論從哪裡出發,一定是跑不了一圈的情況二:rest[i] = gas[i]-cost[i]為一天剩下的油,i從0開始計算累加到最後一站,如果累加沒有出現負數,說明從0出發,油就沒有斷過,那麼0就是起點。
  • 程式設計師算法基礎——貪心算法
    前言貪心是人類自帶的能力,貪心算法是在貪心決策上進行統籌規劃的統稱。
  • LeetCode Top 100 高頻算法題45. Jump Game II
    由於公眾號做了改版,為了保證公眾號的文章可以準時推送到你手裡,大家記得點擊上方藍色」菜鳥名企夢「,將咱們的公眾號 加星標置頂 ,在此真誠的表示感謝~LeetCode Top 100高頻算法題,即LeetCode上最高頻的100道求職面試算法題。
  • 一文詳解貪心算法
    也就是說貪心算法並不從整體最優考慮,它所作出的選擇只是在某種意義上的局部最優選擇。當然,希望貪心算法得到的最終結果也是整體最優的。雖然貪心算法不能對所有問題都得到整體最優解,但對許多問題它能產生整體最優解。如單源最短路經問題,最小生成樹問題等。在一些情況下,即使貪心算法不能得到整體最優解,其最終結果卻是最優解的很好近似。
  • Java 實現貪心算法實例介紹
    假定問題可以分解,並且在過程的每一步都選擇局部最優即「貪心選擇」,那麼可以稱為貪心算法。這裡的重點是問題「可拆分」:即問題可以被描述為一組相似的子問題。大多數情況下,貪心算法都採用遞歸實現。即使有諸多限制,像計算資源限制、限制執行時間、API 或其它限制,貪心算法仍然有辦法找到合理的解決方案。
  • 一文搞懂貪心算法
    顧名思義,貪心算法總是作出在當前看來最好的選擇。也就是說貪心算法並不從整體最優考慮,它所作出的選擇只是在某種意義上的局部最優選擇。當然,希望貪心算法得到的最終結果也是整體最優的。雖然貪心算法不能對所有問題都得到整體最優解,但對許多問題它能產生整體最優解。如單源最短路經問題,最小生成樹問題等。
  • 小白帶你學---貪心算法
    貪心算法(Greedy Algorithm) 簡介貪心算法,又名貪婪法,是尋找最優解問題的常用方法,這種方法模式一般將求解過程分成
  • 貪心算法:合併區間
    局部最優可以推出全局最優,找不出反例,試試貪心。那有同學問了,本來不就應該合併最大右邊界麼,這和貪心有啥關係?有時候貪心就是常識! - 1) flag = true;   // 最後一個區間也合併了                i++;                                // 繼續合併下一個區間            }            // start和end是表示intervals[i - 1]的左邊界右邊界,所以最優intervals[i]區間是否合併了要標記一下
  • 用經典例題輕鬆幫你搞定貪心算法
    運用貪心算法求解問題時,會將問題分為若干個子問題,可以將其想像成俄羅斯套娃,利用貪心的原則從內向外依次求出當前子問題的最優解,也就是該算法不會直接從整體考慮問題,而是想要達到局部最優。貪心算法最關鍵的部分在於貪心策略的選擇,貪心選擇的意思是對於所求問題的整體最優解可以通過一系列的局部最優選擇求得。而必須注意的是,貪心選擇必須具備無後效性,也就是某個狀態不會影響之前求得的局部最優解。
  • C語言最常用的貪心算法就這麼被攻克了
    貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。貪心算法沒有固定的算法框架,算法設計的關鍵是貪心策略的選擇。必須注意的是,貪心算法不是對所有問題都能得到整體最優解,選擇的貪心策略必須具備無後效性(即某個狀態以後的過程不會影響以前的狀態,只與當前狀態有關。)
  • 真正了解貪心算法,這是一篇精華入門總結...
    本文介紹了貪心算法,是一種在每一步選擇中都採取在當前狀態下最有利的選擇,從而得到最優的算法。
  • leetcode算法之貪心
    今天來盤一盤 **貪心算法 ** 這類題目使用python刷題分類整理的筆記,請參考: https
  • 這幾道經典例題幫你輕鬆搞透貪心算法
    運用貪心算法求解問題時,會將問題分為若干個子問題,可以將其想像成俄羅斯套娃,利用貪心的原則從內向外依次求出當前子問題的最優解,也就是該算法不會直接從整體考慮問題,而是想要達到局部最優。貪心算法最關鍵的部分在於貪心策略的選擇,貪心選擇的意思是對於所求問題的整體最優解可以通過一系列的局部最優選擇求得。而必須注意的是,貪心選擇必須具備無後效性,也就是某個狀態不會影響之前求得的局部最優解。
  • 跟耿老師學Java:貪心算法與老鼠走迷宮
    單擊閱讀原文下載原始碼:連結:https://pan.baidu.com/s/18EvAMu89mjxusQf_8LnPxA提取碼: 8ty61..貪心算法   貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。
  • 貪心算法與近似算法
    1 貪心算法1.1 教室調度問題 假設有如下課程表,你希望將儘可能多的課程安排在某間教室上。實際上,算法可能簡單得讓你大吃一驚。具體做法如下。 (1) 選出結束最早的課,它就是要在這間教室上的第一堂課。 (2) 接下來,必須選擇第一堂課結束後才開始的課。同樣,你選擇結束最早的課,這將是要在這間教室上的第二堂課。重複這樣做就能找出答案!下面來試一試。美術課的結束時間最早,為10:00 a.m.,因此它就是第一堂課。
  • C語言最常用的貪心算法就這麼被攻略了
    貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。貪心算法沒有固定的算法框架,算法設計的關鍵是貪心策略的選擇。必須注意的是,貪心算法不是對所有問題都能得到整體最優解,選擇的貪心策略必須具備無後效性(即某個狀態以後的過程不會影響以前的狀態,只與當前狀態有關。)
  • 算法思想簡介(分制),貪心(DJS)動態分配(dp)回溯(萬能)
    算法思想簡介(分制(分開在遞歸),貪心(DJS),動態分配(dp,解決多變化條件),回溯(萬能,深度優先))不管是動態規劃,還是回溯都是在可選擇 條件固定時,進行選擇 ,都會用到遞歸調用。不同的是:貪心最好理解,從頭開始找最優結果一直到最後。