From b2c317a3b9e244db0341c4bef5a6d45801c18e45 Mon Sep 17 00:00:00 2001 From: tokuhirat <54652919+tokuhirat@users.noreply.github.com> Date: Wed, 25 Jun 2025 08:37:20 +0900 Subject: [PATCH] Create 213. House Robber II.md --- 213. House Robber II/213. House Robber II.md | 95 ++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 213. House Robber II/213. House Robber II.md diff --git a/213. House Robber II/213. House Robber II.md b/213. House Robber II/213. House Robber II.md new file mode 100644 index 0000000..bb287ba --- /dev/null +++ b/213. House Robber II/213. House Robber II.md @@ -0,0 +1,95 @@ +# 213. House Robber II +## STEP1 +- 何も見ずに解いてみる +- 0番目と n-1 番目を考えるとややこしいので、場合分けして直線のケースで解けばよさそう。 +```python +class Solution: + def rob(self, nums: List[int]) -> int: + if len(nums) <= 1: + return nums[0] + + def rob_linear(nums: List[int]) -> int: + max_gain_robbed = nums[0] + max_gain_skipped = 0 + for i in range(1, len(nums)): + prev_max_gain_robbed = max_gain_robbed + max_gain_robbed = max_gain_skipped + nums[i] + max_gain_skipped = max(max_gain_skipped, prev_max_gain_robbed) + return max(max_gain_skipped, max_gain_robbed) + + return max(rob_linear(nums[:-1]), rob_linear(nums[1:])) +``` +#### memo +時間計算量: $O(n)$ +空間計算量: $O(1)$ + +## STEP2 +### プルリクやドキュメントを参照 +- https://github.com/olsen-blue/Arai60/pull/36/files + - 関数名の inline は関数のインライン化が想起されそう。in_line であればOKか。上のSTEP1で書いた rob_linear は微妙で rob_linearly の方がよさそう。 + - https://github.com/olsen-blue/Arai60/pull/36/files#r1974943323 + > begin <= x < end の区間とする + - なるほど。シンプルになってすごい。 + +再帰バージョンを書いてみる。区間の端のうち含まれる start を動かした方がわかりやすいと思いました。 +```python +import functools + + +class Solution: + def rob(self, nums: List[int]) -> int: + if len(nums) == 1: + return nums[0] + + @functools.cache + def rob_from_index(start: int, stop: int) -> int: + length = stop - start + if length == 1: + return nums[start] + if length == 2: + return max(nums[start], nums[start + 1]) + return max( + rob_from_index(start + 2, stop) + nums[start], + rob_from_index(start + 1, stop), + ) + + return max(rob_from_index(0, len(nums) - 1), rob_from_index(1, len(nums))) +``` + +- https://github.com/hayashi-ay/leetcode/pull/50/files + - 関数内関数を書かないと微妙に異なる処理を読み解かないといけないので読みにくさを感じた。 +- 198\. House Robber の内容ですが、nums[0] に関する処理もループに入れられる。 +```python + def rob_linear(nums: List[int]) -> int: + max_gain_robbed = 0 + max_gain_skipped = 0 + for i in range(len(nums)): + prev_max_gain_robbed = max_gain_robbed + max_gain_robbed = max_gain_skipped + nums[i] + max_gain_skipped = max(max_gain_skipped, prev_max_gain_robbed) + return max(max_gain_skipped, max_gain_robbed) +``` +- 関数内関数の引数は nums で良いか微妙。nums 自体を渡しているわけではないため。money_list のようにした方が良いかもしれない。 +- len(nums) == 0 の場合は IndexError でよいと思っています。奪う家がない状況で 0円得られますというのは違いそう。ValueError にした方が呼び出し元にとってはわかりやすいかもしれない。結局はこの関数の使用想定によって異なるがあまりイメージできなかった。 + +## STEP3 +### 3回ミスなく書く +```python +class Solution: + def rob(self, nums: List[int]) -> int: + if len(nums) <= 1: + return nums[0] + + def rob_linearly(nums: List[int]) -> int: + max_gain_robbed = 0 + max_gain_skipped = 0 + for i in range(len(nums)): + prev_max_gain_robbed = max_gain_robbed + max_gain_robbed = max_gain_skipped + nums[i] + max_gain_skipped = max(max_gain_skipped, prev_max_gain_robbed) + return max(max_gain_skipped, max_gain_robbed) + + return max(rob_linearly(nums[:-1]), rob_linearly(nums[1:])) +``` + +3分,3分,2分で3回Accept