Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions 198/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 198. House Robber

- 動的計画法を書いた


https://github.com/naoto-iwase/leetcode/pull/40
の実装2: without_lastとwith_lastの二変数だけで良い
- sol2.py

> このコードはスレッドセーフティーという意味でどうなっているでしょうか。

- cacheを使う場合(メモ化再帰)、キャッシュはthread safe: multi-threadで使用できる

https://github.com/hroc135/leetcode/pull/33#discussion_r1899009212
> フィボナッチになりそうですね。黄金比の n 乗なので 1.6^n くらいです
メモがない場合の計算量
https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0


メモ化再帰も書いておく (sol3.py)
14 changes: 14 additions & 0 deletions 198/sol1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
raise ValueError("The input list is empty")

if len(nums) < 2:
return max(nums)
Comment on lines +6 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

制約からテストケースでは守られているのですが、len(nums)==0 だと ValueError が送出されますね。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほど。実務を意識してそのような例外処理も加えようと思います。


max_nums = [nums[0], max(nums[0], nums[1])] + [0] * (len(nums) - 2)

for i in range(2, len(nums)):
max_nums[i] = max(max_nums[i - 1], max_nums[i - 2] + nums[i])

return max_nums[-1]
17 changes: 17 additions & 0 deletions 198/sol2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
raise ValueError("The input list is empty")

if len(nums) < 2:
return max(nums)

max_with_last = nums[0]
max_without_last = 0
Comment on lines +9 to +10
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的には with/without よりも robbed/skipped がしっくりきました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回はこのままにしておきます。
max_with_lastは必ずしも最後の要素を選択するわけではなく (max_with_last = max(max_with_last, max_without_last + nums[i])で前者が選ばれた場合)、robbed/skippedよりもwith/withoutの方がこの意味を残せると考えたためです。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

仰るとおり、robbed_last といいつつ直近の家を盗まない、ということがありますね。あんまり良くない命名でした。

ChatGPTと壁打ちした感じ、以下の選択肢もありそうでした。

  • max_through_last, max_through_second_last
    • with(out) が「取る(盗む)」ニュアンスを生む可能性をさらに下げられそう
  • max_up_to_i_minus_1, max_up_to_minus_2
    • たぶん好みではないでしょうが

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

フォローアップありがとうございます、参考にさせていただきます。
たしかに through だと「必ずしも選択しない」の意味は残せそうですね。
変数名はLLMが得意な領域だと思うので自分も迷ったら投げてみようと思います。


for i in range(1, len(nums)):
next_max_without_last = max_with_last
max_with_last = max(max_with_last, max_without_last + nums[i])
max_without_last = next_max_without_last

return max_with_last
16 changes: 16 additions & 0 deletions 198/sol3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from functools import cache


class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
raise ValueError("The input list is empty")

@cache
def rob_helper(idx):
if idx < 2:
return max(nums[: idx + 1])

return max(rob_helper(idx - 1), rob_helper(idx - 2) + nums[idx])

return rob_helper(len(nums) - 1)