-
Notifications
You must be signed in to change notification settings - Fork 0
198. House Robber #37
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,162 @@ | ||
| # Step1 | ||
|
|
||
| かかった時間:12min | ||
|
|
||
| 計算量:nums.length=Nとして | ||
|
|
||
| 時間計算量:O(N) | ||
|
|
||
| 空間計算量:O(N) | ||
|
|
||
| DP | ||
| ```python | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if len(nums) < 3: | ||
| return max(nums) | ||
|
|
||
| maximum_amount_so_far = [0] * len(nums) | ||
| maximum_amount_so_far[0] = nums[0] | ||
| maximum_amount_so_far[1] = max(nums[0], nums[1]) | ||
| for i in range(2, len(nums)): | ||
| maximum_amount_so_far[i] = max( | ||
| maximum_amount_so_far[i - 1], | ||
| nums[i] + maximum_amount_so_far[i - 2] | ||
| ) | ||
|
|
||
| return maximum_amount_so_far[-1] | ||
| ``` | ||
| 思考ログ: | ||
| - 現時点までの最大金額を順に考えていく | ||
| - 一個前の家でお金を盗んだかどうかで場合わけ | ||
| - ```if len(nums) <= 2:```の方が意図が分かりやすかったかも | ||
| - 因みに```len(nums) == 1```だけ特殊扱いすれば良いのだが、ここは好みかなと | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| @cache | ||
| def _rob_helper(i): | ||
| if i == 1: | ||
| return max(nums[0], nums[1]) | ||
| if i == 0: | ||
| return nums[0] | ||
| return max(_rob_helper(i - 2) + nums[i], _rob_helper(i - 1)) | ||
|
|
||
| return _rob_helper(len(nums) - 1) | ||
| ``` | ||
| 思考ログ: | ||
| - numsの長さ上限が100なので、再帰も問題ない | ||
|
|
||
| # Step2 | ||
|
|
||
| 講師役目線でのセルフツッコミポイント: | ||
|
|
||
| 参考にした過去ログなど: | ||
| - https://github.com/nittoco/leetcode/pull/39 | ||
| - https://github.com/nittoco/leetcode/pull/39#discussion_r1855954945 | ||
| - 最大金額を更新していく方法(多重代入) | ||
| - 最大金額を更新していく方法 | ||
| - 前回盗んだかどうかで分けて管理する方法 | ||
| - https://github.com/seal-azarashi/leetcode/pull/33 | ||
| - 配列を使わない方法、これ前回も頭から落ちていた | ||
| - https://github.com/Mike0121/LeetCode/pull/47 | ||
| - スレッドセーフの議論 | ||
| - GILについて | ||
| - https://docs.python.org/ja/3.6/c-api/init.html | ||
| - https://github.com/Ryotaro25/leetcode_first60/pull/36 | ||
| - https://github.com/Yoshiki-Iwasa/Arai60/pull/50 | ||
| > 各家の前に、泥棒の手下が一人ずつ立って、前から伝言をもらって、最後のところで求めたい数字を知りたいとします。 | ||
| >「伝言」の内容は「ここまで最大いくら取れる、俺の眼の前の家に盗みに入らないとすると最大いくら取れる」の二つだけじゃないですか。 | ||
| - https://github.com/Kitaken0107/arai60/pull/2 | ||
| - https://github.com/goto-untrapped/Arai60/pull/36 | ||
| - https://github.com/fhiyo/leetcode/pull/36 | ||
| - https://github.com/YukiMichishita/LeetCode/pull/16 | ||
| - https://github.com/sakupan102/arai60-practice/pull/36 | ||
| - なるほど | ||
| ```python | ||
| max_sum_before_1, max_sum_before_2 = max(max_sum_before_1, max_sum_before_2 + nums[i]), max_sum_before_1 | ||
| ``` | ||
| - https://github.com/shining-ai/leetcode/pull/35 | ||
| - maxのdefault | ||
| - https://docs.python.org/ja/3/library/functions.html#max | ||
| - https://github.com/hayashi-ay/leetcode/pull/48 | ||
|
|
||
| 配列を使わない方法1 | ||
| ```python | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if len(nums) <= 2: | ||
| return max(nums) | ||
|
|
||
| # numsのi番目を盗んだかどうかで場合わけ | ||
| # i = 1で初期化しておく | ||
| max_money_skipped_i = nums[0] | ||
| max_money_robbed_i = nums[1] | ||
|
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. 個人的にはskippedを0、robbedをnum[0]にした方が好みです。(初期化の意図もわかりやすいので)
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. ありがとうございます。 2つ前の値を使うからi=2スタートだと決め打ちしていたんだと思います。 |
||
| for i in range(2, len(nums)): | ||
| max_money_skipped_i, max_money_robbed_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. 変数のアンパックを使っていて変数名が長いとごてごてしますね。 現場では多くの場合、def の後に docstring を書くし、関数名ももう少ししっかりしているので、もう少し文脈があるはずです。また、変数名にコメントをつけるのも一つでしょう。 |
||
| max(max_money_robbed_i, max_money_skipped_i), | ||
| max_money_skipped_i + nums[i] | ||
| ) | ||
|
|
||
| return max(max_money_robbed_i, max_money_skipped_i) | ||
| ``` | ||
| 思考ログ: | ||
| - O(1)の方法が頭から抜けていた | ||
| - ```nums[i]```を取るかどうかで場合わけ | ||
| - 1つ前、2つ前の最大金額を管理する方法もあるが、個人的にはこちらの方が自然だった | ||
|
|
||
| 配列を使わない方法2 | ||
| ```python | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if len(nums) <= 2: | ||
| return max(nums) | ||
|
|
||
| # 現在地点から1つ前、2つ前の時点での盗める金額の最大値を管理する | ||
| max_money_2_step_back = nums[0] | ||
| max_money_1_step_back = max(nums[0], nums[1]) | ||
| for i in range(2, len(nums)): | ||
| max_money = max(max_money_2_step_back + nums[i], max_money_1_step_back) | ||
| # 次のループのためにアップデート(i+1から見て2or1 step back) | ||
| # i-2(2-step-back) i-1(1-step-back) i(current) | ||
| # i-1(2-step-back) i(1-step-back) i+1(current) | ||
| max_money_2_step_back = max_money_1_step_back | ||
| max_money_1_step_back = max_money | ||
|
|
||
| return max(max_money_2_step_back, max_money_1_step_back) | ||
| ``` | ||
| 思考ログ: | ||
| - 1つ前、2つ前の最大金額を管理する方法も書いてみたが、少し詰まった | ||
| - 今(max_money)、1つ前、2つ前の3地点で考えればいい | ||
| - 1つ前、2つ前を更新するには今=>1つ前、1つ前=>2つ前と推移させればいい | ||
|
|
||
| # Step3 | ||
|
|
||
| かかった時間:3min | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| if len(nums) <= 2: | ||
| return max(nums) | ||
|
|
||
| # i番目を盗むかどうかで場合わけ | ||
| max_money_skipped_i = nums[0] | ||
| max_money_robbed_i = nums[1] | ||
| for i in range(2, len(nums)): | ||
| max_money_skipped_i, max_money_robbed_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. 本当はこっちの方が読みやすいと思うのですが、仕方がないですね。 max_money_skipped_i = max(max_money_skipped_i, max_money_robbed_i)
max_money_robbed_i = max_money_skipped_i + nums[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. いっそのこと別途変数を用意してしまうとか?少しやりすぎですかね? class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) <= 2:
return max(nums)
max_money_skipped_last = nums[0]
max_money_robbed_last = nums[1]
for i in range(2, len(nums)):
max_money_skipped = max(max_money_skipped_last, max_money_robbed_last)
max_money_robbed = max_money_skipped_last + nums[i]
max_money_skipped_last = max_money_skipped
max_money_robbed_last = max_money_robbed
return max(max_money_skipped_last, max_money_robbed_last)
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(max_money_skipped_i, max_money_robbed_i), | ||
| max_money_skipped_i + nums[i] | ||
| ) | ||
|
|
||
| return max(max_money_skipped_i, max_money_robbed_i) | ||
| ``` | ||
| 思考ログ: | ||
|
|
||
| # Step4 | ||
|
|
||
| ```python | ||
| ``` | ||
| 思考ログ: | ||
|
|
||
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.
_iの部分がちょっと気になりました、なんかループの中でi番目のi-1番目として使われるのでややこしいなと感じました。まあこの部分がなくても良いのかなとも思います。