Featured image of post 從LeetCode學演算法 - 110 Array (16) / Greedy Algorithm (1)

從LeetCode學演算法 - 110 Array (16) / Greedy Algorithm (1)

0881. Boats to Save People (Medium)

寫在前面

目前0元挑戰賽 的活動已經開始囉!
只要修課後三個月內完課且成功錄取新工作並撰寫心得,
課程就會全額退費喲!請使用下面連結看更詳細的規則說明:

零元求職挑戰賽 Python 組|從 LeetCode 學演算法 + 面試成功指南 http://bit.ly/zeroclg

抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)
Python Taiwan的連結第100篇的文章 底下,
公開分享到你的臉書、按讚該篇文章、並留言告訴我說,
「你最喜歡這一整個系列的哪一篇?為什麼?」或
「除了從LeetCode學演算法系列以外,
你還想要看到關於什麼方向的文章?」

超過20則留言的話 (有完成以上步驟的才算),我們就抽一組
「從Leetcode學演算法|進階篇」+「從Leetcode學演算法|面試篇」
課程的免費兌換券進行贈送!

期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)

容筆者工商一下,
「從Leetcode學演算法|進階篇」 開放預購啦!
這次選了40道難度加深的LeetCode題目,
同樣也會細部解說對應的技巧及須要掌握的演算法!
同時這次購買進階篇的話,
額外還加贈**「從Leetcode學演算法|面試篇」** !
當中包含了面試準備須知分享及訪談國內外不同經驗的工程師
讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作
初學想轉職 還是正在工作 ,都能夠從中得到收穫呦!
有興趣的朋友可以使用下面的早鳥優惠~
「從Leetcode學演算法|進階篇」+「從Leetcode學演算法|面試篇」
https://bit.ly/leetcodeadv

Question

The i-th person has weight people[i], and each boat can carry a maximum weight of limit.

Each boat carries at most 2 people at the same time, provided the sum of the weight of those people is at most limit.

Return the minimum number of boats to carry every given person. (It is guaranteed each person can be carried by a boat.)

Example 1

1
2
3
Input: people = [1,2], limit = 3
Output: 1
Explanation: 1 boat (1, 2)

Example 2

1
2
3
Input: people = [3,2,2,1], limit = 3
Output: 3
Explanation: 3 boats (1, 2), (2) and (3)

Example 3

1
2
3
Input: people = [3,5,3,4], limit = 5
Output: 4
Explanation: 4 boats (3), (3), (4), (5)

Note :

  • 1 <= people.length <= 50000
  • 1 <= people[i] <= limit <= 30000

分析/解題

有一群人people,當中第i個人的重量是people[i],
且每艘船最重可以載重limit,同時最多只能乘載2個人,
乘載的重量最多為limit(剛好的話也可以)
試計算並回傳最少所需裝載所有人的船的數量。

乍看之下,這題是不是有點像以前的Two Sum?
但再仔細想想,就會發現,
由於我們並不一定要每艘船都裝載到limit的重量,
所以並不能夠形成相加等於特定和的關係。

那麼該怎麼處理呢?
如果這群人是由小到大排列的話,
不管如何最重的那些人都還是要上船,
所以我們先挑最右邊的(最重的人)上船。
接下來這艘船還能不能帶人呢?
我們就再幫忙找最左邊的(最輕的人)看能不能湊一組,
可以湊就沒問題,不能湊也無法強求,就只好讓這個人自己一條船囉!
這樣搭配下,我們就可以盡可能先幫較重的人找看看能不能組起來,
因此會是所需求的船隻數量會是最小的。

上面這樣子的概念,被稱為貪婪演算法(Greedy Algorithm)
貪婪演算法的核心精神,在於先找到一個方法,
使得每次盡可能都處理所有可以操作的單位,
再依序往下做處理,這樣的方法是對總體來說也是最佳 的時候,
就符合貪婪演算法的特性。
請讀者務必留意,
如果像是動態規劃(Dynamic Programming) 這類型的問題,
就顯然不會符合 貪婪演算法的作法,
因為局部的最佳解,不見得會是全局的最佳解

所以對這題來說,當我們排序完這群人以後,
從最重的開始盡可能幫其安排組合,對總體來說就會是最好的。

因此,我們的大體解法應該如下:

  1. 先將people由小到大排序
  2. l = 0, r = people.length - 1, res = 0 (用來記錄需要幾艘船)
  3. 使用一個迴圈,當 l ≤ r 時,進行以下操作:
    3–1. 如果 people[l]+people[r]<= limit 時,
    代表可以捎上index l 的人,此時將** l遞增。
    3–2. 由於
    所有人的重量都一定小於limit** ,(題目說的)
    所以people[r]一定可以占一艘船 (不管people[l]有沒有上船),
    所以我們將r遞減 ,並且將res遞增 ,這艘船我們就處理完囉!
  4. 回傳res 即為答案。

讀者可能會問:咦?那l和r重疊 的話怎麼辦?
問得好!重疊的話,由於不論怎麼樣r都會遞減,
所以重疊的時候,事實上就是相當於3–1沒有任何作用
但並沒有影響到我們要計算的res,對吧XD?

依此,寫成程式碼如下:

Java

Java的話使用Arrays.sort(),
其他部分應該相當直觀。
這裡提供LeetCode的另一種解法,
由於有limit的限制,所以我們可以利用長度為limit+1的陣列,
來達到排序的效果(這相當於O(limit)的空間去換取時間複雜度降低)

Python

Python的排序則直接對串列進行.sort()即可,
讀者請記得sorted()函式是產生一個新的排序的串列,別搞混喲!

面試實際可能會遇到的問題

「時間/空間複雜度?」
(O(NlogN)/O(1),N為people的長度。
如果是使用Java附上的參考解的話則是O(limit)/O(limit))

相似及延伸

Special Thanks suggestions/corrections from viewers:
(歡迎提供意見協助更正歐~)

從LeetCode學演算法,我們下次見囉,掰~

想看看其他題目嗎?
歡迎從第零篇 找你想要的!

同時追蹤粉專以獲得更多新文章的通知:
跟著Desolve學程式

另外,「從Leetcode學演算法|基礎篇」 已經回原價囉,
先前的優惠碼會失效,但這邊仍然為讀者保留了300塊的折抵,
雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD),
如果你還是想先試試基礎課的話,
300元折抵的連結 在這邊:
https://bit.ly/1desolve

共發表了 171 篇文章 ‧ 總計 311.6k
使用 Hugo 建立
主題 StackJimmy 設計