Skip to content

Valid Parentheses #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
213 changes: 213 additions & 0 deletions validParentheses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# Valid Parentheses

## step1

- 最初の十分で下のコードを書いた
- ([)]のような事例に対応できていない。

```python
class Solution:

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.

ありがとうございます。手作業でやるならどうするかを考えたことはなかったので次から試してみたいと思います。

def isValid(self, s: str) -> bool:
brackets = {"round":0,"curly":0,"square":0}
for character in s:
if character == "(":
brackets["round"] += 1
elif character == ")":
brackets["round"] += -1
if brackets["round"] < 0:
return False
elif character == "{":
brackets["curly"] += 1
elif character == "}":
brackets["curly"] += -1
if brackets["curly"] < 0:
return False
elif character == "[":
brackets["square"] += 1
elif character == "]":
brackets["square"] += -1
if brackets["square"] < 0:
return False

if all(val == 0 for val in brackets.values()):
return True
else:
return False
```

- わからなかったため[回答](https://leetcode.com/problems/valid-parentheses/solutions/3399077/easy-solutions-in-java-python-and-c-look-at-once-with-exaplanation/)を見た

```python
class Solution:
def isValid(self, s: str) -> bool:
stack = []
for c in s:
if c in '({[':
stack.append(c)
else:
if not stack or (c == ')' and stack[-1] != '(') or (c == '}' and stack[-1] != '{') or (c == ']' and stack[-1] != '['):
return False
stack.pop()
return not stack

```

- stackに入れて後ろから確かめていくのは思いつかなかった
- `return not stack`で返すとbool値になるのは知らなかった

Choose a reason for hiding this comment

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

- [[引用符]]は"と'で違いがあるのだろうか?
- [pep8](https://peps.python.org/pep-0008/#string-quotes)によるとどちらでもいいらしい
- 文字列内にどちらかが含まれる場合はバックスラッシュを使うためもう一つを使うべき
- ペアのdictを定義して下のようにやった方が簡単になるのではないかと思った

```python
class Solution:
def isValid(self, s: str) -> bool:
stack = []
pair = {')':'(','}':'{',']':'['}
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.

承知しました。今度からは気をつけたいと思います。

for c in s:
if c in '({[':
stack.append(c)
else:
if not stack or stack[-1] != pair[c]:
return False
stack.pop()
return not stack
```

- `if len(stack) == 0 or stack.pop() != brackets[s[i]]:`としてもできるらしい
- list.pop(i)について<https://docs.python.org/ja/3/tutorial/datastructures.html>
- リストのi番目の要素を削除しそれを返す。何も指定されない場合は最後の要素を返す。

## step2 他の人のコードを見る・コードの改善

[valid parentheses は、チョムスキー階層、タイプ-2、文脈自由文法だから、プッシュダウンオートマトンで書ける](https://discord.com/channels/1084280443945353267/1201211204547383386/1202541275115425822)
- [[チョムスキー階層]]
- チョムスキーによって提唱された形式文法の分類のための理論的枠組み
- タイプ0~3がある
- タイプ2:文脈自由文法
- 非終端記号が単独で生成規則に従う
- プッシュダウンオートマトンで書ける
- プッシュダウンオートマトン
- 要素
- 状態集合
- 有限の内部状態を保つ
- 入力
- スタック
- 初期状態
- スタック初期記号
- スタックが空であることを示すもの
- 状態遷移関数
- 現在の状態・入力・スタックのトップ記号に基づいて次の状態とスタック操作を決定する
- 自分が書いているコードのやり方に名前がついてるということ
- 今後調べてみる
## [再帰下降構文解析](https://www.youtube.com/watch?v=b83HIvQ8bqY)でも解ける
- 難しそうだったので今後の課題とする
## [moriさん](https://github.com/hroc135/leetcode/pull/6/files/a54d34fc4e5ed6ed09a40bf695d55924b8a9b42f#diff-bfc7c633525ec3f5b431366ade3df4c7bbc2592dca465c6b4fc39882d99dec66)
- やり方はほぼ同じ
- Lifo Queueを用いている
- [[スタックとキュー]]のうちスタックを実装するもの
- 主にスレッド通信に用いられる
- スタック操作に効率化されている
- 今回はListの順番の要素が必要ないためLifoQueueを用いるのも有用と考えられる。
- dictをopen_to_closeで実装した方が直感的なので良いと考える
```python
from queue import LifoQueue


class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {
Copy link

Choose a reason for hiding this comment

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

こちらの対応の取り方のほうが、括弧の対応と一致しているため、個人的には好きです。

"(": ")",
"{": "}",
"[": "]"
}
open_brackets = LifoQueue()
Copy link

Choose a reason for hiding this comment

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

queue.LifoQueue() は内部でスレッド同期が取られるため、取られないデータ構造に比べて動作が遅いと思います。プロデューサー・コンシューマーパターンを実装するときなど特別な場合を除き、避けたほうがよいと思います。


for c in s:
if c in open_to_close:
open_brackets.put(c)
continue
if open_brackets.empty():
return False
top = open_brackets.get()
if c != open_to_close[top]:
return False

return open_brackets.empty()
```

### 自分の改善

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {
"(":")",
"{":"}",
"[":"]"
}
stack = []

for c in s:
if c in open_to_close:
stack.append(c)
continue
if not stack or c != open_to_close[stack.pop()]:
return False

return not stack
```

collections.dequeを用いてみる

- [Listとdequeの計算量の違い](https://wiki.python.org/moin/TimeComplexity)
- append,popどちらもO(1)なので今回は差がない

Choose a reason for hiding this comment

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

定数倍の処理を無視していて、少し乱暴に思えます。dequeの方は双方向LinkedListを使っているため、単にStackとして使用するならListに比べてオーバーヘッドがあると思います。

Copy link

Choose a reason for hiding this comment

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

計算量に興味がありすぎるかもしれません。計算量は計算時間を見積もるための手段です。だから、定数倍にも興味を持ちましょう。また、内部実装とできることの差異により注目しましょう。


```python
from collections import deque


class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {
"(":")",
"{":"}",
"[":"]"
}
stack = deque()

for c in s:
if c in open_to_close:
stack.append(c)
continue
if not stack or c != open_to_close[stack.pop()]:
return False

return not stack
```

いろいろ調べていたら4時間くらいかけてしまった。これで良いのだろうか?

Choose a reason for hiding this comment

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

LeetCode解くことがゴールではないのでいいのではないでしょうか。慣れれば調べるのに掛かる時間も減ると思います。

Copy link

Choose a reason for hiding this comment

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

問題にもよりますが、この問題からは相当たくさんのことを連想することが分かったと思います。はじめはそれでいいのです。


## step3

step2と同じ

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {
"(":")",
"{":"}",
"[":"]"
}
stack = []

for c in s:
if c in open_to_close:
stack.append(c)
continue
if not stack or c != open_to_close[stack.pop()]:

Choose a reason for hiding this comment

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

自分はifの条件を分けて書いてしまいますね。あとstackの操作もif分とは別にやると思います。まあ好みかもしれないです。

Copy link

Choose a reason for hiding this comment

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

スタックの底に番兵を置いておくのも一応手としてはあります。

return False

return not stack

Choose a reason for hiding this comment

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

まあ選択肢の幅として。
return len(stack) == 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.

ここの表記を変えるとどのようなニュアンスの違いがでるのかお聞きしたいです。それとも個人の好みに過ぎないのでしょうか?

Choose a reason for hiding this comment

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

個人的には好みの範囲かなと思ってます。どの記法に慣れているかだったりPython以外の馴染みのある言語でも読みやすさも変わってきそうですし。個人的にはlen(stack) == 0の方が配列の要素が0であることを確認しているのが直感的に分かるのでlenを使う方が好みです。
大事なのは、色々書き方があることを知っているうえで自分が気に入っているのを使うというプロセスかなと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど、ありがとうございます。
好みを決めれるほど記法を知らないのでコメントいただけて助かります。

Copy link

Choose a reason for hiding this comment

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

PEP-8 と Google Style Guide は strings, lists, tuples は implicit でということでしたね。
趣味の範囲でしょう。大規模開発などでは周りを見て合わせましょう。
https://google.github.io/styleguide/pyguide.html#2144-decision
https://peps.python.org/pep-0008/#other-recommendations:~:text=For%20sequences%2C%20(strings%2C%20lists%2C%20tuples)%2C%20use%20the%20fact%20that%20empty%20sequences%20are%20false%3A

```