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
101 changes: 101 additions & 0 deletions leetcode/arai60/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# 20. Valid Parentheses
問題リンク: https://leetcode.com/problems/valid-parentheses/
言語: Python

# Step1
* 訪れた文字をスタックに積む
* 訪れた文字が閉カッコの場合かつ、ひとつ前の文字が対応する開カッコの場合、スタックから2回popする

```python
class Solution:
def isValid(self, s: str) -> bool:
if len(s) <= 1:
return False

visited_chars = deque()
Copy link

@h1rosaka h1rosaka Jul 9, 2025

Choose a reason for hiding this comment

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

(step2,3含め)dequeではなくlistでも良いのかなと思いました。(popとappendしかしてなさそうなため。)

Copy link

Choose a reason for hiding this comment

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

コードの動きの上では変わらないと思いますが、適切なコンテナを使ったほうが意図が伝わりやすいか思います。

Choose a reason for hiding this comment

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

deque である必要はないというのはその通りでして、追加すると collections から import しているというのは明記したいですね (LeetCode だとデフォルトで import されているので)。


for c in s:
visited_chars.append(c)
if len(visited_chars) != 1:
if c == ")" and visited_chars[-2] == "(":
visited_chars.pop()
visited_chars.pop()
if c == "]" and visited_chars[-2] == "[":
visited_chars.pop()
visited_chars.pop()
if c == "}" and visited_chars[-2] == "{":
visited_chars.pop()
visited_chars.pop()

if len(visited_chars) == 0:
return True
else:
return False
```
* 解答時間: 1:03:46
- 途中でスタックを使った方法に気づいてからは15分くらい
- 後ろから2番目を参照する方法は `visited_chars` のサイズを事前に検証しないといけないのであまり綺麗ではないと思った

# Step2
## 他人のコードを読む
* https://github.com/maeken4/Arai60/pull/6
- C++
- スタックを使ったアルゴリズム
- 事前にカッコの対応関係(キー:開カッコ、値:閉カッコ)を辞書で持っておく
- 今後のカッコの種類の変更に対応しやすくなる意味でも良いと思った
- 自分の場合は両方のカッコを同時にスタックに積んでいたが、これは開カッコに対応する**閉カッコ**のみをスタックに積む方法
- 文脈自由文法(プッシュダウンオートマトン)で文法を定義できる
- `S → (S) | SS | ε`
- コンパイラの字句解析そのものか…

* https://github.com/ryosuketc/leetcode_arai60/pull/6
- Python
- カッコの対応関係(キー:閉カッコ、値:開カッコ)を辞書で持っておく
- アルゴリズムは同じ
- 変数名がわかりやすい

## 読みやすく直したコード
```python
class Solution:
def isValid(self, s: str) -> bool:
closing_to_opening_brackets = {")": "(", "]": "[", "}": "{"}
Copy link

Choose a reason for hiding this comment

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

opening_to_closing_brackets = {"(": ")", "[": "]", "{": "}"}

と、開きカッコを先に持ってきたほうが読みやすいと思います。ロジックが少し変わりますが、過去のコードレビューを参照すれば見つかると思います。

unmatched_open_brackets = deque()

for bracket in s:
if bracket in closing_to_opening_brackets:
if not unmatched_open_brackets:
return False
actual_bracket = unmatched_open_brackets.pop()
expected_bracket = closing_to_opening_brackets[bracket]
if actual_bracket != expected_bracket:
return False
else:
unmatched_open_brackets.append(bracket)
Copy link

Choose a reason for hiding this comment

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

(好みの問題かもしれませんが)、ひだりカッコの処理が先にあったくれた方が個人的には頭に入りやすいかもと思いました。(左かっこの方がシンプルなので、シンプルなものが先に片付いてくれて方が、最後に残っているより少し楽に感じるため)


return not unmatched_open_brackets
```

# Step3
```python
class Solution:
def isValid(self, s: str) -> bool:
closing_to_opening_bracket = {")": "(", "]": "[", "}": "{"}
unmatched_brackets = deque()
Copy link

Choose a reason for hiding this comment

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

全体的に読みやすいと思います!個人的にはstep2のようにunmatched_open_bracketsと明示してくれた方が読むのが楽に思いました。


for bracket in s:
Copy link

Choose a reason for hiding this comment

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

問題の制約で起きえないですが、文字列にかっこ以外の文字が含まれる可能性を考えると、bracketとして良いのだろうか、という気持ちになりました。

if bracket in closing_to_opening_bracket:
Copy link

Choose a reason for hiding this comment

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

93行目の処理を先に書いたほうが読みやすいと思いました。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.9kpbwslvv3yv

Choose a reason for hiding this comment

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

+1 です

if not unmatched_brackets:
return False
actual_bracket = unmatched_brackets.pop()
expected_bracket = closing_to_opening_bracket[bracket]
if actual_bracket != expected_bracket:
return False
else:
unmatched_brackets.append(bracket)

return not unmatched_brackets
```
* 解答時間
- 1回目: 3:44
- 2回目: 4:27
- 3回目: 3:51