LeetCode #198 House Robber - 刷題之旅
1 題目描述
有一排房子,每個房子裡面有一定的錢,但是不能連續偷兩個房子,否則會報警,在不觸發報警的狀況下求最多可以偷到多少錢。
2 解法
按照之前的介紹LeetCode 課前預習 - 掌握 Dynamic Programming 的思維指南,我很推薦把每一種步驟都嘗試寫出來看看,分別是:
- Step1: Recursive
- Step2: Recursive with Memoization
- Step3: Iterative + Tabulation
- Step4: Iterative with Constant Space
Step1: Recursive
一道很典型的通過子問題去解決原問題的題目,所以可以透過遞歸以及動態規劃解決。
假設:知道了前 n - 1 家店
最多能偷的錢數,前 n - 2 家店
最多能偷的錢數。
關係式:如果我們想要知道前 n 家商店
最多能偷多少錢,我們可以選擇偷
- 偷:偷
第 n 家商店
+前 n - 2 家商店
最多能偷的錢數。 - 不偷:不偷
第 n 家商店
+前 n - 1 家商店
最多能偷的錢數。
最小問題:如果今天 n = 0
,那麼就是0
,如果n = 1
,那麼就是nums[0]
。
n = 0
:表示沒有店家可以偷n = 1
:表示只有一家店可以偷,那也只能偷了
1 | def rob(self, nums: List[int]) -> int: |
Step2: Recursive with Memoization
那我們就思考,是不是某些已經算過的子問題,我們可以直接拿來用,這樣就不用重複計算了。
因此我們需要一個dict來記錄已經算過的子問題。使用dict的好處是可以使用O(1)的時間複雜度來查找。
1 | def rob2(self, nums: List[int]) -> int: |
Step3: Iterative + Tabulation
接下來,因為Recursive的缺點是有call stack size的限制,所以我們可以使用Iterative,來避免這個問題
1 | def rob3(self, nums: List[int]) -> int: |
Step4: Iterative with Constant Space
最後,我們再思考一下,目前時間複雜度已經到極限了,但是空間複雜度是不是可以再省一點?因為我們只需要前面兩個步驟的結果就可以了。
1 | def rob4(self, nums: List[int]) -> int: |
3 總結
這題不難,我覺得所有的dp題目最有挑戰性的就是要先知道他的recursive formula,只要能夠實作出來,其他的優化都是小case。
本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 Shannon's Blog 🐟 技術 | 生活 | 旅行! 如果你覺得我的文章有幫助,希望你可以到我的 github 給我一個 star ⭐️ Shannon Blog Repo
評論