iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
Software Development

天天 LeetCode,立地成佛:三十天從頭開始學演算法系列 第 6

[Day 6] Jump Game:有種直觀解法叫 Greedy

  • 分享至 

  • xImage
  •  

今天要介紹和 Dynamic Programming 有點相似的 Greedy。

Greedy 的核心概念很簡單:選擇你覺得最好的方案就對了。這個選擇的過程是單向的,今天遇到了第一個分岔點,你選擇了道路 A,那就必須一直走下去直到終點,不能中途覺得不對,又想回過來換成道路 B。而且,這種方法不會去評估 A、B、C 三條路,再看看確定要走哪條,是直接做出決定,然後在這個決定的基礎上再去做下一個決定。

要使用 Greedy 的條件和 Dynamic Programming 蠻類似的,就是問題的最佳解也會包含子問題的最佳解。在這個情況下,我們才可以一條路走到黑,並確保只要每個選擇點的決定都是最好的,就會得到最完美的結果。當然,條件不成立也是可以使用啦,但得到的就可能是近似解而不是最佳解了。

舉個實際的例子,假設今天要買東西,要怎麼達到效益最大化呢?當然是買你覺得 CP 值最高的東西了。於是我們可以列出一個物品清單,把 價值 / 價格 = CP 值,優先選擇 CP 值最高的東西,如果選完後還有剩下的錢,再買 CP 值第二高的東西,這樣買到沒錢為止,聽起來不難吧。

這就是有名的背包問題(Knapsack Problem),目的是要在有限的空間中,裝進價值最多的物品。背包問題又有很多種變形題,像是每種物品只能挑 0 或 1 個,或是可以切成非整數個帶走,又或者每種物品最多可帶走的數量都不一樣、有各自的限制,大家有興趣的可以搜尋看看。


今天的問題跟昨天有點像,可以想像成跳樓梯問題。每個台階最多可以跳的階數都有規定,假如限制是 3,那走 1、2、3 階都可以。這個問題是要去判斷,在給定的限制下,有沒有辦法走到最後一階。

這個問題可以反推來解,假設今天可以從 n-1 走到 n 階,問題就縮小成第 1 階能不能跳到倒數第 n 階。n-1 到 n 階是否能到是很好判斷的,所以我們就能一路往回推到起點求答案。

https://ithelp.ithome.com.tw/upload/images/20200913/20129662mRmiiCB7xR.png

// javascript
var canJump = function(nums) {
    let position = nums.length - 1
    for (let i = nums.length - 1; i >= 0; i--) {
      if (i + nums[i] >= position) {
        position = i
      }
    }
    return position == 0
};

// C++
class Solution {
public:
    bool canJump(vector<int>& nums) {
      int position(nums.size() - 1);
      for(int i = nums.size() - 1; i >= 0; i--)
        if (i + nums[i] >= position) {
          position = i;
        }
      return position == 0;
    }
};

最後順帶一提,不同語言的執行效率差距蠻驚人的,這邊提供上面兩個解法的執行結果給大家看看。實際原因就暫時略過,之後有空再來研究。

| |Runtime|Memory|
|javascript|68 ms|12.8 MB|
|C++ |16 ms|38 MB|

以上,文章有任何問題或錯誤都歡迎留言,感謝閱讀~


上一篇
[Day 5] Climbing Stairs:從下而上的 Dynamic Programming
下一篇
[Day 7] Maximum Depth of Binary Tree: 走進 tree 的世界
系列文
天天 LeetCode,立地成佛:三十天從頭開始學演算法12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言