# Week1 - Greedy Algorithm ###### tags: `Leetcode` ## 55. Jump Game 思路:指針 A 負責從左到右遍歷數組元素,指針 B 負責追蹤當前最遠可跑的位置。若 A 指針與 B 指針重疊,且指針所在位置之數值為 0,則表示失敗。若 B 指針所在位置大於等於數組長度,則表示成功。 ```python class Solution(object): def canJump(self, nums): """ :type nums: List[int] :rtype: bool """ max_reach = 0 l = len(nums) for i in range(l): max_reach = max(max_reach, i + nums[i]) if max_reach >= l-1: return True elif i == max_reach: return False ``` + **Links** + https://www.youtube.com/watch?v=i5L_onhWULc ## 45. Jump Game II 定義函數 $d(r) =$ 到位置 $r$ 所需的最少步數,$d(r)$ 滿足 + 單調遞增。 + $d(0) = 0$。 + 走 $k$ 步可走的最大距離等於 $\max\{r + num[r] \, | d(r) = k \}$。 + 失敗條件:$\max d^{-1}(k) <= \max d^{-1}(k-1)$。 思路:$k$ 負責紀錄步數,指針 A 負責從左到右遍歷數組元素,指針 B 負責紀錄走 $k$ 步最遠可到的位置,指針 C 負責紀錄走 $k+1$ 步最遠可到的位置。若 A 指針與 B 指針位置重疊,將 $k$ 值加 $1$,將 B 指針位置更新至 C 指針位置,C 指針位置保持不變;若 A 指針已位於數組最右邊,輸出 $k$。 ```python class Solution(object): def jump(self, nums): """ :type nums: List[int] :rtype: int """ k, l = 0, len(nums) curr_largest_step, next_largest_step = 0, nums[0] for i in range(l): if i == l-1: return k next_largest_step = max(next_largest_step, nums[i] + i) if i == curr_largest_step: k += 1 curr_largest_step = next_largest_step ``` + **Links** + https://www.youtube.com/watch?v=2A1CkbghE6Y) ## 134. Gas Station 我們知道若 $gas$ 之和小於 $cost$ 之和,則不存在路徑滿足條件,反之,$gas$ 之和若大於等於 $cost$ 之和,則存在路徑,證明見下圖。 思路:指針 A 負責從左到右遍歷數組元素,指針 B 負責紀錄本次路徑的起始位置,定義個變數 $total$, $remain$ 分別紀錄數組 $gas$ 之和減去數組 $cost$ 之和與當前路徑 $gas$ 之減去 $cost$ 之和,若 $remain$ 值小於 0,則結束這次的路徑,並以下一點為起始,重新開始路徑,直至遍歷完數組。若最後 $total$ 為負值,輸出 $-1$,反之,輸出 指針 B 所在位置。 ![](https://i.imgur.com/6Kn57bv.png =600x400) ```python class Solution(object): def canCompleteCircuit(self, gas, cost): """ :type gas: List[int] :type cost: List[int] :rtype: int """ k, l = 0, len(gas) remain, total = 0, 0 for i in range(l): net = (gas[i] - cost[i]) total += net remain += net if remain < 0: remain = 0 k = i + 1 return -1 if total < 0 else k ``` ## 179. Largest Number ```python class Compare(str): def __lt__(x, y): return x + y < y + x class Solution(object): def largestNumber(self, nums): """ :type nums: List[int] :rtype: str """ a_list = sorted(map(str, nums), key=Compare, reverse=True) largest_num = "".join(a_list) return "0" if largest_num[0] == "0" else largest_num ``` + **Links** + https://stackoverflow.com/questions/63164064/unable-to-understand-lt-method + https://hackmd.io/thsnM8y2Sx-AhF16ZFgZBg ## 122. Best Time to Buy and Sell Stock II ![](https://i.imgur.com/kdhQOdB.png) ```python class Solution(object): def maxProfit(self, prices): """ :type prices: List[int] :rtype: int """ profit = 0 for i in range(len(prices)-1): profit += max((prices[i+1] - prices[i]), 0) return profit ``` + **Links** + https://hackmd.io/gAlljfGbS_intn3k1gQomA ## 11. Container With Most Water ```python class Solution(object): def maxArea(self, height): """ :type height: List[int] :rtype: int """ left, right = 0, len(height) -1 area = min(height[left], height[right]) * (right - left) while left < right: if height[left] < height[right]: left += 1 else: right -= 1 area = max(area, min(height[left], height[right]) * (right - left)) return area ``` **數學證明**:假設 $i, j$ 為最佳組合 $$ area(i, j) = \max \{area(i, j)| 0< i < j < l\} $$ 其中,$l$ 為數組的長度。我們要證明雙指針演算法會移動到 $i, j$ 這個組合。假設 A, B 分別為左右兩個指針,不失一般性,假設指針 A 先移動到位置 $i$ 且指針 B 還在 $j$ 點的右邊。因為 $i, j$ 為最佳組合,具有下列性質 $$ h(i) > h(n), \quad \forall n < i, \\ h(j) > h(m), \quad \forall m > j. $$ 考慮下列兩種情況 + 若 $h(i) <= h(j)$:我們知道盛水的高度取決於短邊,因此, $$ h(i) > h(m), \quad \forall m>j. $$ + 若 $h(i) > h(j)$: 根據下列不等式 $$ h(i) > h(j) > h(m), \quad \forall m>j. $$ 因此,指針 $m$ 需要往左移動。