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
149 changes: 149 additions & 0 deletions 20. Valid Parentheses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# step1
- 紙面上で入力パターンを考えてみた
- 入力を取り出していって (,{,[ が来ていないのに ),},] が先に来るパターンはfalseになる
- ( が来たら丸かっこフラグをたてる、{ がきたら波かっこフラグを立てる。フラグが立っていないのに 閉じる側のかっこがきたらfalse
- ループでi番目とi+1番目の入力を比較して、開きかっこがきたら閉じるかっこが来るまでi+2,i+3と進めていく
- 例えば入力が([])だったら、i番目:( i+1番目:[ でfalseなので ( を保持しして 一致する閉じかっこが来るまでループを回す
- などを考えていたが、入力が(([]))のときなどの判断が難しかったので、一旦別の方法に切り替える
- (([]))のときに 最初の(を0番目としたら、入力の一番最後である5番目に)が来ればよい。1番目の ( に対応する ) はstrの長さ-1番目に、[ に対応する ] は strの長さ-2番目に来る。鏡のように対称の位置にあるかっこを探す形であれば実現できそう
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

同じ失敗しました。
上手くいかなかったのは()(]を考えてないからなんですね。やっと理由がわかりました。
失敗の反省など書いてるの良いと思います。

Copy link
Copy Markdown
Owner Author

@wanwan87 wanwan87 May 12, 2026

Choose a reason for hiding this comment

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

ありがとうございます、良いアイデアだ!と思ってコードを書き始めちゃいましたが、(問題文で提示されている)テストケースは少なくとも試しておいたほうが良さそうですね


ここまでで1時間ぐらいかかっている。

以下間違い

```python
class Solution:
def isValid(self, s: str) -> bool:
for i in range(len(s)):
if len(s) == 1:
return False
if s[i] =='(':
if s[len(s)-i-1] ==')' or s[i+1] ==')':
return True
elif s[i] =='{':
if s[len(s)-i-1] =='}' or s[i+1] =='}':
return True
elif s[i] =='[':
if s[len(s)-i-1] ==']' or s[i+1] ==']':
return True
else:
return False
return True
```

- sの長さ奇数のときは即falseにしてよさそう
- 今のコードだと "()(]" とかで破綻しそう。()の段階で s[i+1] ==')' で trueにしてしまっているから。
- 即trueにしない場合、"()"のときの")"に対応するかっこを探しに行って破綻しそう
- 破綻しないようにsの長さ分forを回さず、len(s)/2も考えたが、結局"()(]"でダメそう
- 破綻しないようにパッチを当てていく方法だと、新しく追加した条件によって、もともと解決できていた個所も気付かないうちにカバーできなくなってしまっていたりする
- 対称の位置のかっこを探す方法を思いついた時に"(([]))"のような対称性のある入力のみを考えてしまったが、対称性のない入力も考えるべきだった。

時間をかけすぎてしまったので答えを見て整理。

```python3
class Solution:
def isValid(self, s: str) -> bool:
i=0
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

二項演算子の両側にスペースが入っているものと入っていないものが混ざっているのが気になりました。

参考までにスタイルガイドへのリンクを共有いたします。

https://peps.python.org/pep-0008/#other-recommendations

Always surround these binary operators with a single space on either side: assignment (=), augmented assignment (+=, -= etc.), comparisons (==, <, >, !=, <=, >=, in, not in, is, is not), Booleans (and, or, not).

https://google.github.io/styleguide/pyguide.html#s3.6-whitespace

Surround binary operators with a single space on either side for assignment (=), comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), and Booleans (and, or, not). Use your better judgment for the insertion of spaces around arithmetic operators (+, -, *, /, //, %, **, @).

なお、このスタイルガイドは“唯一の正解”というわけではなく、数あるガイドラインの一つに過ぎません。チームによって重視される書き方や慣習も異なります。そのため、ご自身の中に基準を持ちつつも、最終的にはチームの一般的な書き方に合わせることをお勧めします。

# stackに格納していく
a=[]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

a という変数名からは、中にどのような値が格納されるか想像しにくく感じます。 open_brackets 等、中に格納される値が想像しやすい変数名を付けるとよいと思います。

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.

ありがとうございます、中身がわかる変数名を意識します

for i in range(len(s)):
# ({[の場合、スタックにプッシュする
if s[i]=='('or s[i]=='['or s[i]=='{':
a.append(s[i])
# )}]の場合
else:
# stackが空の場合はfalse
if not a:
return False
# stackに({[が入っている場合はtopと比較する
top=a.pop()
# 入力のかっことtopが一致しない場合はfalse。
if s[i]==')'and top!='(':
return False
if s[i]==']'and top!='[':
return False
if s[i]=='}'and top!='{':
return False
# stackが空になったらtrueを返す
return len(a)==0
```


# step2

- 変数名aは変えたい。stackとか?
- https://github.com/hiro111208/leetcode/pull/6/changes
- ({[はdict型に格納すると簡潔に書けそう
- 命名は (キー)_to_(値) が良いらしい
- 今回の場合だと,open_to_closeという変数に{"(":")"}のように入れていく。
- return not stackがスタイルガイド的にはいい。あくまでガイドなのでチームでのルールに則る。
- https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0
- 番兵を置いておくことで条件式を1つ減らせるらしい
- stackが空の場合の条件に入らなくなるので削減できる(if not aの条件)
- >“(aiu)[eo]” が入力としてきたときに、プログラムの挙動として好ましいのは何だと考えますか?
- 余計な入力は無視してtrueにする?
- これはちょっと怖いかも。関数の使用者かユーザーになにかしらのFBを返したい。
- 入力がおかしいのでfalseにする?
- なんでfalseになっているか気づかれないかも。
- エラーとして例外を投げる?
- 要件によるかもしれないが、かっこ以外の文字は入れないでくださいと返すとか。
- 今回のコードの場合はforの中で確認すればよさそう。if char in open_to_closeのcontinueの時点で、開きかっこではないことが確定しているので、その下に閉じかっこでないことを確認(if char not in set(open_to_close.value())して、エラーを出す。
- プッシュダウンオートマトン
- 聞いたことはなかったが、オートマトン+スタックを組み合わせた計算モデル
- https://www.krrk0.com/pushdown-automaton/
- チョムスキー階層
- 形式言語を生成する形式文法の包含階層(形式言語の階層)で、句構造文法(phrase structure grammar)の階層」などともいう
- 形式言語:プログラミング言語を含む一部の人工言語や、機械可読なドキュメント類など、用法の変化に関して自然言語に対して厳格である言語。自然言語は話者集団によってあいまいさが残されたり、用法がうつろいゆく。
- チョムスキー階層のタイプ2がプッシュダウンオートマトンらしい。
- https://ja.wikipedia.org/wiki/%E3%83%81%E3%83%A7%E3%83%A0%E3%82%B9%E3%82%AD%E3%83%BC%E9%9A%8E%E5%B1%A4


if char != open_to_close[last_open_brackets]にする場合は、stackから#をpopしてきた時に辞書にないのでエラーとなってしまうので、辞書に登録するか、getでキーが存在しない場合に第二引数である空文字を返すようにする。

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {"(" : ")", "{" : "}", "[" : "]"}
stack = ["#"]
for char in s:
if char in open_to_close:
stack.append(char)
continue
last_open_brackets = stack.pop()
if char != open_to_close.get(last_open_brackets,""):
return False
return stack == ["#"]
```


# step3

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {"(":")","{":"}","[":"]"}
stack = ["#"]
for char in s:
if char in open_to_close:
stack.append(char)
continue
last_opne_bracket = stack.pop()
if char != open_to_close.get(last_opne_bracket,""):
return False
return stack == ["#"]
```

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {"(":")","{":"}","[":"]"}
stack = ["#"]
for char in s:
if char in open_to_close:
stack.append(char)
continue
last_open_bracket = stack.pop()
if char != open_to_close.get(last_open_bracket,""):
return False
return stack == ["#"]
```