diff --git a/198. House Robber.md b/198. House Robber.md new file mode 100644 index 0000000..1adce4f --- /dev/null +++ b/198. House Robber.md @@ -0,0 +1,97 @@ +### Step1 + +- 大学受験の漸化式っぽい問題 +- 配列やresult_so_farあたりの命名は迷った + +```python + +class Solution: + IS_ROBBING = 1 + NOT_ROBBING = 0 + + def rob(self, nums: List[int]) -> int: + max_amount_can_rob = [[0] * 2 for _ in range(len(nums) + 1)] + result_so_far = 0 + for passed_house_count in range(1, len(nums) + 1): + max_amount_can_rob[passed_house_count][self.IS_ROBBING] = ( + max_amount_can_rob[passed_house_count - 1][self.NOT_ROBBING] + + nums[passed_house_count - 1] + ) + max_amount_can_rob[passed_house_count][self.NOT_ROBBING] = result_so_far + result_so_far = max( + max_amount_can_rob[passed_house_count][self.IS_ROBBING], + max_amount_can_rob[passed_house_count][self.NOT_ROBBING], + ) + return result_so_far +``` + +### Step2 + +- よく考えたら、いくつ家を通過したかを表すindexはいらない(こういうのつけちゃう癖がある) + - 前の状態をたくさん持ってる必要がある時以外はいらないということか + - ただ、IS_ROBBINGの変数が何を表しているかわからなくなるかも(一応コメントをつけた) +- max_amount_can_rob[self.RECENT_PASSED]の値が、for文の1回目で出てくる時と2回め以降で意味が違ってくる(しかも1行目でそれ使って代入してる)のはわかりにくい? + +```python + +class Solution: + # 最新の家から盗んだかどうか + IS_ROBBING = 1 + RECENT_PASSED = 0 + + def rob(self, nums: List[int]) -> int: + max_amount_can_rob = [0] * 2 + result_so_far = 0 + for house_count in range(1, len(nums) + 1): + max_amount_can_rob[self.IS_ROBBING] = ( + max_amount_can_rob[self.RECENT_PASSED] + nums[house_count - 1] + ) + max_amount_can_rob[self.RECENT_PASSED] = result_so_far + result_so_far = max( + max_amount_can_rob[self.IS_ROBBING], + max_amount_can_rob[self.RECENT_PASSED], + ) + return result_so_far +``` + +- https://github.com/fhiyo/leetcode/pull/36/files + - 結構読み解くのに時間かかった。思考回路が多分自分と違った。 + - 多分、前2つのうちどちらが最後に盗んだかで分けよう!というのが思考回路として最初に出てる?ので、今の家で盗んだか盗んでないかで分けようというのが自分と思考回路が違ったのかな + - フィボナッチ数列のちょっと変えたやつみたいな(説明が下手) + - max_money_so_farの、[1]と[0]がそれぞれ何を表しているのかわからない、というのはあるかも +- https://github.com/seal-azarashi/leetcode/pull/33 + - twoBackとあるので、やはり最後に盗んだのが2つ前か1つ前かという思考らしい + - どうせ保存する値は2つなので、わざわざ配列にする必要ないのは確かに + - numsが空の場合の例外処理をちゃんと考えてなかったが、上の自分の実装の場合は結果的に0になる(書かなくて良いにしてもちゃんと考えた方が良かった) +- https://github.com/Ryotaro25/leetcode_first60/pull/36 +- https://github.com/rossy0213/leetcode/pull/20/files + - dpの長さをlen(nums) + 2になるのはマジックナンバー感がありあまり好みでない +- https://github.com/YukiMichishita/LeetCode/pull/16 + - 今を含むかで場合わけしており、自分と思考が近め +- https://github.com/shining-ai/leetcode/pull/35 + - currentではなくmax_amount_1_beforeを返すのはあんまり納得いかないかも + - maxのdefaultは勉強になったが、あまり好まないかも +- https://github.com/hayashi-ay/leetcode/pull/48/files + - 結構前2つのmaxという発想の人は多いみたい +- https://github.com/Yoshiki-Iwasa/Arai60/pull/50/files + - rob_3が自分の思考回路と近そうだが、命名がしっくりこなかった(コメントがあったのでスムーズに読めはした) + +## Step3 + +- DPらしさが跡形もなくなったが、以下のようになった + - 自然な気がする +- 長さが0, 1の場合の例外処理がいらないのも好み + +```python + +class Solution: + def rob(self, nums: List[int]) -> int: + prev_result = 0 + result_so_far = 0 + recently_passed = 0 + for money_amount_in_house in nums: + result_so_far = max(prev_result, recently_passed + money_amount_in_house) + recently_passed = prev_result + prev_result = result_so_far + return result_so_far +```