題目
思路
- 跟 House Robber 很像,只差在房子的排列變成頭尾相連,有沒有辦法把這題拆解,變成能用上第一版 House Robber 的解題方法?譬如把環形變回直排?
- 變成環形之後多出來的限制讓我們可以把這題分成以下三種情況:
- 搶第一個、不搶最後一個:加入第三種情況,等同於可以視為直排,但只考慮到倒數第二個
- 不搶第一個、搶最後一個:加入第三種情況,等同於可以視為直排,但從第二個開始考慮
- 第一個和最後一個都不搶:可與前兩種情況合併
- 最後把以上三種情況合併為粗體的兩種情況,轉為第一版 House Robber 問題,接下來只需取兩種情況錢比較多的就是答案
- 因為現在需多考慮起始 index,我們把第一版解法的遞迴函式改為多傳入起始 index,並同樣用
@cache避免同樣的inner_rob(i, j)重複計算- Base case 寫法:
- 考慮一開始
j比i大的情況,一路因為inner_rob(i, j - 1),inner_rob(i, j - 2)而減少的情況:j == i + 2時:下兩個遞迴節點為inner_rob(i, i + 1),inner_rob(i, i)j == i + 1時: 下兩個遞迴節點為inner_rob(i, i),inner_rob(i, i - 1)
- 此時可以寫出 base case 的兩種情況
j == i,j < i
- 考慮
nums數字最小的幾種情況,看看遞迴是否正常收斂 or 結果是否正確len(nums) == 3:max(inner_job(0, 1), inner_job(1, 2))-> 正常收斂
len(nums) == 2:max(inner_job(0, 0), inner_job(1, 1))-> 結果正確
len(nums) == 1:max(inner_job(0, -1), inner_job(1, 0))- 此時得出的答案為
0,是錯的,所以 base case 需多考慮這種情況,加入len(nums) == 1時的判斷處理
- 考慮一開始
- Base case 寫法:
- 取錢比較多的情況即為答案:
return max(inner_rob(0, len(nums) - 2), inner_rob(1, len(nums) - 1))
Python3 solution:
1 | def rob(self, nums: List[int]) -> int: |
如果不用 @cache:
1 | def rob(self, nums: List[int]) -> int: |