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
146 changes: 146 additions & 0 deletions 20. Valid Parentheses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# step 1
stackを使う有名問題みたいなイメージ。

文字列を左から順に見ていって、閉じかっこがきたら**それに対応する開きかっこ**がstack上に存在するかを
調べるということの太字部分を意識して、close_to_openと書いていた。

文字列の長さをnとして
- time complexity: O(n)
- space complexity: O(n) (Auxiliary space: O(n))

```python3
class Solution:
def isValid(self, s: str) -> bool:
stack = []
close_to_open = {')': '(', '}': '{', ']': '['}
for parenthesis in s:
if parenthesis in close_to_open:
if stack == [] \
or stack[-1] != close_to_open[parenthesis]:
return False
stack.pop()
else:
stack.append(parenthesis)
return stack == []
```
# step 2
参考
- https://github.com/katataku/leetcode/pull/6/files
- https://google.github.io/styleguide/pyguide.html#214-truefalse-evaluations
> For sequences (strings, lists, tuples), use the fact that empty sequences are false, so if seq: and if not seq: are preferable to if len(seq): and if not len(seq): respectively.
- 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
- PEP8, google style guideともに、sequenceに対してはlen()を用いてのブールチェックはしない。
- https://en.wikipedia.org/wiki/Bracket
open, closeの他に、left, rightもあるという話
> Brackets are typically deployed in symmetric pairs, and an individual bracket may be identified as a 'left' or 'right' bracket or, alternatively, an "opening bracket" or "closing bracket"
- 実装はほぼ同じだった。相違点はclose_to_openをopen_to_closeとしていた点と、
stackをopening_parenthesesにしていた点。前者については、初期化部分は`)(`こういう文字列が並んでいるより、`()`のほうが見やすい感覚があるのでより直感的だと思った。
後者に関しては、stackの中にはopen parenthesesしか入らないから、こちらの実装の方が読みやすく感じた。
- https://github.com/konnysh/arai60/pull/6
- open, close parenthesisそれぞれに対する処理を関数化する解法があった。
- こちらもopen_to_closeを使用していた。
- https://github.com/tarinaihitori/leetcode/pull/7/files
- if, elseなどで処理が離れる場合は、continueやreturnしたりして、下まで見に行かなくていいようしたい。というより、離れてると読みにくいなと感じられると良さそう。
- https://docs.python.org/3/library/collections.html#deque-objects
dequeをつかってstackとすることも可能
- https://github.com/python/cpython/blob/main/Modules/_collectionsmodule.c#L81-L83
> Data for deque objects is stored in a doubly-linked list of fixed length blocks.

複数データが入れられる固定サイズのブロックをdoubly-linked listで繋いでいるみたい。こうすることでmalloc(), free()の回数を減らしている。(cpythonのソースは大量のマクロと長い行数から読めるわけないだろと思っていたが、doubly-linked listを使った一つのノードに一つのデータが対応するタイプのdequeは実装したことがあったので、このくらいのコードならなんとなくの気持ちくらいはわかりそうだなぁと思った。)

- https://google.github.io/styleguide/pyguide.html#284-decision
> Use default iterators and operators for types that support them, like lists, dictionaries, and files. The built-in types define iterator methods, too. Prefer these methods to methods that return lists, except that you should not mutate a container while iterating over it.
```
Yes: for key in adict: ...
if obj in alist: ...
for line in afile: ...
for k, v in adict.items(): ...

No: for key in adict.keys():
for line in afile.readlines(): ...
```

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {
'(': ')',
'{': '}',
'[': ']'
}
open_bracket_stack = []
for bracket in s:
if bracket in open_to_close:
open_bracket_stack.append(bracket)
continue

if (not open_bracket_stack \
or open_to_close[open_bracket_stack[-1]] != bracket):
return False

open_bracket_stack.pop()
return not open_bracket_stack
Comment on lines +71 to +82

Choose a reason for hiding this comment

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

Suggested change
open_bracket_stack = []
for bracket in s:
if bracket in open_to_close:
open_bracket_stack.append(bracket)
continue
if (not open_bracket_stack \
or open_to_close[open_bracket_stack[-1]] != bracket):
return False
open_bracket_stack.pop()
return not open_bracket_stack
stack = []
for bracket in s:
if bracket in open_to_close:
stack.append(bracket)
continue
elif not stack or open_to_close[stack.pop()] != bracket:
return False
return not stack

popと条件分岐を同時にできるのでこのような書き方もありかなと思いました。

```

- `open_bracket_stack`という名前はopen_bracketしか入らないこと・初期化時にリストを代入しているが用法としてはstackとして使うことがわかるようにした。
- `or open_to_close[open_bracket_stack[-1]] != bracket):`はインデントして、下の部分が条件式ではないことを明確にした。[PEP8](https://peps.python.org/pep-0008/#indentation)では特に指定がなかった。
Copy link

Choose a reason for hiding this comment

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

こういうフォーマットは、それなりに幅があって正解がないものであるということです。
autoformatter たとえば black などを参考にするのも一つでしょう。
https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#how-black-wraps-lines

# step 3
```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {
'(': ')',
'{': '}',
'[': ']'
}
open_bracket_stack = []
for bracket in s:
if bracket in open_to_close:
open_bracket_stack.append(bracket)
continue
if (open_bracket_stack

Choose a reason for hiding this comment

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

自分は2つのif文に分けるかなと思いますが、好みかもしれないです。

and open_to_close[open_bracket_stack[-1]] == bracket):
open_bracket_stack.pop()
continue
return False
return not open_bracket_stack
```

# step 4
- フォーマットには厳格な正解がない. formatterが何をしてるのかも参考になるという話
- https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#how-black-wraps-lines
- [google style guide](https://google.github.io/styleguide/pyguide.html#383-functions-and-methods:~:text=the%20point%20of%20having%20style%20guidelines%20is%20to%20have%20a%20common%20vocabulary%20of%20coding%20so%20people%20can%20concentrate%20on%20what%20you%E2%80%99re%20saying%20rather%20than%20on%20how%20you%E2%80%99re%20saying%20it.)もこの話に通じるなと感じた
> The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you’re saying rather than on how you’re saying it.
- dictではなく、open, close parenthesesのペアをそれぞれリストで所持する解法もあった
- step 3では、うまく次に進める場合はcontinueというループの書き方をしていたが、if文を分けるかもという意見があった。

その他
- backslashを行繋ぎ
- これをすると、backslash以降にコメントを入れた際に動かなくなるためよろしくない。
- trailing commas:縦に並び、closing parenthesisと最後の要素が同一行にないのならつけた方が無難
- [PEP 8](https://peps.python.org/pep-0008/#when-to-use-trailing-commas)
- [google style guide](https://google.github.io/styleguide/pyguide.html#341-trailing-commas-in-sequences-of-items)

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

for parenthesis in s:
if parenthesis in open_to_close:
open_parentheses_stack.append(parenthesis)
continue

if not open_parentheses_stack:
return False
if open_to_close[open_parentheses_stack[-1]] != parenthesis:
return False
open_parentheses_stack.pop()

return not open_parentheses_stack
```