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
63 changes: 63 additions & 0 deletions 213-House-Robber-II/note.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 213. House Robber II

https://leetcode.com/problems/house-robber-ii/

## step1(まず通す)

輪になっていない場合(198. House Robber)は、目の前の家までで盗める最高額は以下二つの max だった:

- 目の前から盗まない→一つ前の家までの最高額
- 目の前から盗む→二つ前の家までの最高額 + 今の家で盗める額

輪になっていると、リストの先頭と末尾以外は今までと同じだが、先頭と末尾は両方から盗むことはできないので、

1. 先頭を入れてもよくて目の前の家までで盗める最高額
2. 2つ目の家からから始めて(先頭を含めずに)目の前の家までで盗める最高額

の2つを計算し続け、最後の家の 2 と一つ前の家の 1 を比較することになる。

## step2(整形)

append するより最初にlen(nums) の長さを確保した配列用意してから値を入れていく方が見やすいかも。(漸化式っぽい見た目になるので)
→書いてみたが別にそんなことはなかった。初期化の行が増えるだけみづらいかも。

```python
class Solution:
def rob(self, nums: list[int]) -> int:
if not nums:
return 0
if len(nums) == 1:
return nums[0]

max_monies_from_begin = [0] * len(nums)
max_monies_from_begin[0] = nums[0]
max_monies_from_begin[1] = max(nums[0], nums[1])

max_monies_without_begin = [0] * len(nums)
max_monies_without_begin[1] = nums[1]
for i in range(2, len(nums)):
max_monies_from_begin[i] = max(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

同じロジックを 2 回書くより、ロジックを関数にくくりだし、開始インデックスと終了インデックスを 2 種類渡して max を取るほうがシンプルになると思いました。

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_monies_from_begin[i - 1],
max_monies_from_begin[i - 2] + nums[i],
)
max_monies_without_begin[i] = max(
max_monies_without_begin[i - 1],
max_monies_without_begin[i - 2] + nums[i],
)

return max(max_monies_from_begin[-2], max_monies_without_begin[-1])
```

198. House Robber と同じく、配列は不要で2つ前まで覚えていればいいのでそれで書く。

## step3(10分以内にさっとかける \* 3回)

prev と prevprev を return するのは違和感あったので変数名を変えた(これでもあんまりいいとは思わないが)

## step4

> 同じロジックを 2 回書くより、ロジックを関数にくくりだし、開始インデックスと終了インデックスを 2 種類渡して max を取るほうがシンプルになると思いました。

これで書いてみる

実質的な初期値(`nums[begin]` など)をあらかじめ代入して range(begin + 2, end) でループするか、仮の初期値 0 を入れておいて range(begin, end) でループするかは迷う。みて意味がわかりやすいのは前者な気がするが、配列のインデックスの範囲を気にする必要がありちょっと煩雑か。
24 changes: 24 additions & 0 deletions 213-House-Robber-II/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Solution:
def rob(self, nums: list[int]) -> int:
if not nums:
return 0
if len(nums) == 1:
return nums[0]

max_monies_from_begin = [nums[0], max(nums[0], nums[1])]
max_monies_without_begin = [0, nums[1]]
for i in range(2, len(nums)):
max_monies_from_begin.append(
max(
max_monies_from_begin[-1],
max_monies_from_begin[-2] + nums[i],
)
)
max_monies_without_begin.append(
max(
max_monies_without_begin[-1],
max_monies_without_begin[-2] + nums[i],
)
)

return max(max_monies_from_begin[-2], max_monies_without_begin[-1])
31 changes: 31 additions & 0 deletions 213-House-Robber-II/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class Solution:
def rob(self, nums: list[int]) -> int:
if not nums:
return 0
if len(nums) == 1:
return nums[0]

prevprev_from_begin = nums[0]
prev_from_begin = max(nums[0], nums[1])
current_from_begin = 0

prevprev_without_begin = 0
prev_without_begin = nums[1]
current_without_bein = 0

for i in range(2, len(nums)):
current_from_begin = max(
prev_from_begin,
prevprev_from_begin + nums[i],
)
prevprev_from_begin = prev_from_begin
prev_from_begin = current_from_begin

current_without_bein = max(
prev_without_begin,
prevprev_without_begin + nums[i],
)
prevprev_without_begin = prev_without_begin
prev_without_begin = current_without_bein

return max(prevprev_from_begin, current_without_bein)
29 changes: 29 additions & 0 deletions 213-House-Robber-II/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Solution:
def rob(self, nums: list[int]) -> int:
if not nums:
return 0
if len(nums) == 1:
return nums[0]

prev_from_begin = nums[0]
current_from_begin = max(nums[0], nums[1])

prev_without_begin = 0
current_without_begin = nums[1]

for i in range(2, len(nums)):
next_from_begin = max(
prev_from_begin + nums[i],
current_from_begin,
)
prev_from_begin = current_from_begin
current_from_begin = next_from_begin

next_without_begin = max(
prev_without_begin + nums[i],
current_without_begin,
)
prev_without_begin = current_without_begin
current_without_begin = next_without_begin

return max(current_without_begin, prev_from_begin)
22 changes: 22 additions & 0 deletions 213-House-Robber-II/step4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Solution:
def rob(self, nums: list[int]) -> int:
def calculate_max_money(begin: int, end: int) -> int:
prev_max = 0
current_max = 0

for i in range(begin, end):
next_max = max(prev_max + nums[i], current_max)
prev_max = current_max
current_max = next_max

return current_max

if not nums:
return 0
if len(nums) == 1:
return nums[0]

return max(
calculate_max_money(0, len(nums) - 1),
calculate_max_money(1, len(nums)),
)