Skip to content
Open
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
83 changes: 83 additions & 0 deletions problem35/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
## 取り組み方
- step1: 5分以内に空で書いてAcceptedされるまで解く + テストケースと関連する知識を連想してみる
- step2: 他の方の記録を読んで連想すべき知識や実装を把握した上で、前提を置いた状態で最適な手法を選択し実装する
- step3: 10分以内に1回もエラーを出さずに3回連続で解く

## step1
`nums`の要素がi番目までの時、
盗める最大はひとつ前を使うか、使わないで`nums[i]`を使うかの大きい方が答え。
つまり、`amount_total_money`、`prev_amount_total_money`、`prev_prev_amount_total_money`を管理していけば良い。

```python
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
prev_prev_total_amount_money = nums[0]
prev_total_amount_money = max(nums[0], nums[1])
total_amount_money = max(
prev_prev_total_amount_money,
prev_total_amount_money
)
for i in range(2, len(nums)):
total_amount_money = max(
prev_prev_total_amount_money + nums[i],
prev_total_amount_money
)
prev_prev_total_amount_money = prev_total_amount_money
prev_total_amount_money = total_amount_money
return total_amount_money
```

## step2
### 読んだコード
- https://github.com/hayashi-ay/leetcode/pull/48/files
- https://github.com/fhiyo/leetcode/pull/36/files
- https://github.com/nittoco/leetcode/pull/39/files

### 感想
- 変数名が微妙、`max_money_so_far`あたりをつけるべき。
- 更新のループは0からはじめるようにしても良いが、2から始めた方が意図が伝わる気がする。
- メモ化再帰の発想がパッとは思い付かない。規則性がみえたら漸化式をおいてみる->ボトムアップのアプローチと考えがちな気がする。

Choose a reason for hiding this comment

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

再帰を思いつく方法としては、

amount_total_moneyprev_amount_total_moneyprev_prev_amount_total_moneyを管理していけば良い。

という管理対象すべてtotal_moneyなので、つまり単純に前回の結果を使っている、みたいなところを意識すると比較的わかりやすい書き換えができると思います。
この場合、prev_prevが-2、prevが-1なので、この発想だとトップダウンになりやすい気がしました。

※ただし、キャッシュ量を制限しない単純なメモ化再帰だと過去のデータすべて保持してしまうので、メモリ使用量が増えるというのがあります。

Copy link
Owner Author

Choose a reason for hiding this comment

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

コメントありがとうございます。

慣れな気もするので、いただいたアドバイスを元に練習したいと思います。


```python
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) <= 2:
return max(nums)
prev_prev_max_money = nums[0]
prev_max_money = max(nums[0], nums[1])
max_money = None

Choose a reason for hiding this comment

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

これは好みが分かれると思いますが、max_moneyの型がOptional[int]になってしまうので、0で初期化のほうがいいかなと思います。今回の場合はlen(nums) <= 2を処理しているので、下のforループを必ず通ることが保証されていますが、多分max_moneyの型Optional[int]とreturnの型のintで不整合という型エラーになるlinterが多いと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

レビューありがとうございます。
確かに型を統一する意識は持たないといけませんね。気をつけます。


for num in nums[2:]:
max_money = max(
num + prev_prev_max_money,
prev_max_money
)
prev_prev_max_money = prev_max_money
prev_max_money = max_money
return max_money
```

## step3
1,2回目はstep2とほぼ同じになってしまったので、3回目は0番目からループに入れるようにした。悪くない気もする。

```python
class Solution:
def rob(self, nums: List[int]) -> int:
SENTINEL = 0
Copy link

Choose a reason for hiding this comment

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

私はこれを番兵とは呼ばないかなと思います。言葉としては柔らかく使われているのですが、多くの場合、範囲外へのアクセスや条件を吸収するために特殊な値を置いておくことですが、この場合は、単に足していくときの初期値という意味合いが強いので、この値でないと駄目ですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

レビューありがとうございます。

私はこれを番兵とは呼ばないかなと思います。言葉としては柔らかく使われているのですが、多くの場合、範囲外へのアクセスや条件を吸収するために特殊な値を置いておくこと

言われてみれば、おっしゃる通りだなと納得しました。
今回であれば単に0で初期化で良いのですね。

prev_prev_max_money = SENTINEL
prev_max_money = SENTINEL
max_money = SENTINEL

for num in nums:
max_money = max(
num + prev_prev_max_money,
prev_max_money
)
prev_prev_max_money = prev_max_money
Copy link

Choose a reason for hiding this comment

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

prev_prev_max_moneyが少し見にくいかなと感じました。
あまり良い案が思いつきませんが、prev2_max_moneyとかですかね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

レビューありがとうございます。

前々回の〜〜といった日本語をよく見る気がしたので使いましたが、確かにprev_prev_みづらいですね。
"2つ前"であることを明示した書き方の方が良いですね。例えば以下など。

max_profit_two_houses_ago
max_profit_one_houses_ago
max_profit

Copy link

Choose a reason for hiding this comment

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

英語的に正しいかは分かりませんが、ニュアンスはそんな感じです。

prev_max_money = max_money
return max_money
```