-
Notifications
You must be signed in to change notification settings - Fork 0
198. House Robber #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| # 198. House Robber | ||
|
|
||
| ## 1st | ||
|
|
||
| ### ① | ||
|
|
||
| DPで解く解法を何となく覚えていた。漸化式から前2つだけ覚えておけば良いことがわかる。 | ||
|
|
||
| `len(nums) == 2`のときは特別扱いしなくて良かった。 | ||
|
|
||
| 所要時間: 10:43 | ||
|
|
||
| n: len(nums) | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(1) | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if not nums: | ||
| return 0 | ||
| if len(nums) == 1: | ||
| return nums[0] | ||
| if len(nums) == 2: | ||
| return max(nums[0], nums[1]) | ||
| max_money_so_far = [nums[0], max(nums[0], nums[1])] | ||
| for i in range(2, len(nums)): | ||
| prev = max_money_so_far[1] | ||
| max_money_so_far[1] = max(max_money_so_far[1], max_money_so_far[0] + nums[i]) | ||
| max_money_so_far[0] = prev | ||
| return max_money_so_far[1] | ||
| ``` | ||
|
|
||
| ### ② | ||
|
|
||
| メモ化再帰。rob_helperはmax_robbable_money_fromという名前でもいいかもしれない。 | ||
|
|
||
| 所要時間: 7:35 | ||
|
|
||
| n: len(nums) | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(n) | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| @cache | ||
| def rob_helper(i: int) -> int: | ||
| if i == len(nums) - 1: | ||
| return nums[-1] | ||
| if i == len(nums) - 2: | ||
| return max(nums[-2], nums[-1]) | ||
| return max(rob_helper(i + 1), rob_helper(i + 2) + nums[i]) | ||
|
|
||
| if not nums: | ||
| return 0 | ||
| return rob_helper(0) | ||
| ``` | ||
|
|
||
| ### ③ | ||
|
|
||
| 逆からメモ化再帰。こっちの方が素直か。rob_helperはmax_robbable_money_untilという名前でもいいかもしれない。 | ||
|
|
||
| 所要時間: 1:47 | ||
|
|
||
| n: len(nums) | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(n) | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| @cache | ||
| def rob_helper(i: int) -> int: | ||
| if i == 0: | ||
| return nums[0] | ||
| if i == 1: | ||
| return max(nums[0], nums[1]) | ||
| return max(rob_helper(i - 1), rob_helper(i - 2) + nums[i]) | ||
|
|
||
| if not nums: | ||
| return 0 | ||
| return rob_helper(len(nums) - 1) | ||
| ``` | ||
|
|
||
| ## 2nd | ||
|
|
||
| ### 参考 | ||
|
|
||
| - https://discord.com/channels/1084280443945353267/1192736784354918470/1253694708719550516 | ||
|
|
||
| maxはiterableを取れるので、①のmax_money_so_farの初期化は `max_money_so_far = [nums[0], max(nums[:1])]` で良い。 | ||
|
|
||
| - https://discord.com/channels/1084280443945353267/1227073733844406343/1244882790638420060 | ||
| - https://discord.com/channels/1084280443945353267/1201211204547383386/1223216025919553666 | ||
|
|
||
| maxのdefaultキーワードを使って入力がから配列だったときの考慮をしている。 | ||
|
|
||
| 漸化式の初項を0, 二番目の項をnums[0]とする見方もある。 | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if len(nums) < 2: | ||
| return max(nums, default=0) | ||
| max_money_so_far = [0, nums[0]] | ||
| for i in range(1, len(nums)): | ||
| prev = max_money_so_far[1] | ||
| max_money_so_far[1] = max(max_money_so_far[1], max_money_so_far[0] + nums[i]) | ||
| max_money_so_far[0] = prev | ||
| return max_money_so_far[1] | ||
| ``` | ||
|
|
||
| 書いてみると、どちらも趣味の範囲な気がした。 | ||
|
|
||
| - https://discord.com/channels/1084280443945353267/1200089668901937312/1217116484203970701 | ||
|
|
||
|
|
||
| ## 3rd | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if not nums: | ||
| return 0 | ||
| if len(nums) == 1: | ||
| return nums[0] | ||
|
Comment on lines
+126
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. このコードだと
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. たしかに...!気づきませんでした、ありがとうございます。 |
||
| max_money_so_far = [nums[0], max(nums[:2])] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 素直に2変数使うほうが読みやすいかなと思もいました。自分は2周してようやく何をしているかが分かりました。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほど、ありがとうございます。 for i in range(2, len(nums)):
max_money = max(last_max_money, second_last_max_money + nums[i])
second_last_max_money = last_max_money
last_max_money = max_moneyみたいな。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invariant
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. そうですね、そのイメージでした。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Loop invariantをコメントに入れたら、分かりやすくなりそうでしょうか。(max_moneyはどこかで定義する) max_money_so_far = [nums[0], max(nums[:2])] # max_money_so_far: [max_money[0], max_money[1]]
for i in range(2, len(nums)):
# max_money_so_far: [max_money[i - 2], max_money[i - 1]]
prev = max_money_so_far[1]
max_money_so_far[1] = max(max_money_so_far[1], max_money_so_far[0] + nums[i])
max_money_so_far[0] = prev
# max_money_so_far: [max_money[i - 1], max_money[i]]There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so_far はこの場合はそりゃそうだろう感がありませんか。 |
||
| for i in range(2, len(nums)): | ||
| prev = max_money_so_far[1] | ||
| max_money_so_far[1] = max(max_money_so_far[1], max_money_so_far[0] + nums[i]) | ||
| max_money_so_far[0] = prev | ||
| return max_money_so_far[1] | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こちらが自然な気がします。再帰を使う場合はTop Downのアプローチが向いていると思います。②はBottom Upだけど再帰を使っていて見慣れなかったです。