Skip to content
Open
Show file tree
Hide file tree
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
36 changes: 36 additions & 0 deletions executiontime_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import timeit


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

open_brackets = [None] # Put None as a sentinel

for bracket in s:
if bracket in open_to_close:
open_brackets.append(bracket)
else:
last = open_brackets.pop()

if not last or bracket != open_to_close[last]:
return False

return len(open_brackets) == 1


solution = Solution()

s = "()" * 5000

total_time = timeit.timeit(
lambda: solution.isValid(s),
number = 1
)

print(f"入力文字数: {len(s):,}")
print(f"合計実行時間: {total_time * 1_000_000:.3f} us")
95 changes: 95 additions & 0 deletions memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
## 今回解いた問題と次に解く問題
- 今回解いた問題:20. Valid Parentheses(https://leetcode.com/problems/valid-parentheses/description/?envType=problem-list-v2&envId=xo2bgr0r)
- 次に解く問題:703. Kth Largest Element in a Stream(https://leetcode.com/problems/kth-largest-element-in-a-stream/?envType=problem-list-v2&envId=xo2bgr0r)

## Step 1
### 考えたこと
スタックに([{が来るたびに一つずつ積んでいって、)]}が来るたびに一つずつスタックからpopしていく。スタックの名前がスタックなのは少し嫌だと思ったが、他に思いつかなかったのでとりあえずstackにした。時間計算量はO(n)、空間計算量もO(n)。

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

Choose a reason for hiding this comment

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

ありがとうございます!これから意識するようにしてみます。
Pythonでのこのような単純な処理であれば1回0.1us-1us程度と考えて、O(n)でsのlengthが最大10^4のため、最悪でも100us-1000usの範囲内と見積もるイメージでやってみようと思います。
実際にsのlengthを最大にして計測したところ、260usだったため見積もりの範囲内でした。

分岐が多くて読みづらいので、もう少し読みやすく書けないかと思った。

```python
class Solution:
def isValid(self, s: str) -> bool:
stack = []
if not s:
return True
for c in s:
if c in "([{":
stack.append(c)
elif c == ")":
if not stack:
return False
last = stack.pop()
if last == "(":
continue
else:
return False
elif c == "]":
if not stack:
return False
last = stack.pop()
if last == "[":
continue
else:
return False
elif c == "}":
if not stack:
return False
last = stack.pop()
if last == "{":
continue
else:
return False
if not stack:
return True
else:
return False
```
## Step 2
### 読んだコード
- https://github.com/bumbuboon/Leetcode/pull/7/changes
- https://github.com/philip82148/leetcode-swejp/pull/11/changes

### 考えたこと
- 先に[と]みたいにペアを作っておく。open_to_closeのような名前のdictionary型変数がいいか。
- return(len(stack) == 0)だと可読性が高い
- スタックの名前がstackの代わりの名前として、open_bracketsなどがある。
- if not stackの分岐を避けるためにあらかじめstackの中に番兵(Cだと\0などの目印、PythonだとNoneなどか?)を入れておくのも有効。

```python
class Solution:
def isValid(self, s: str) -> bool:
open_brackets = []
open_to_close = {'(' : ')',
'{' : '}',
'[' : ']'}
for c in s:
if c in open_to_close:
open_brackets.append(c)
elif not open_brackets:
return False
else:
last = open_brackets.pop()
if open_to_close[last] != c:
return False
return (len(open_brackets) == 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.

        return not open_brackets

のほうが空かどうかを判定しているという意図が伝わりやすいと思います。

こちらもご参照ください。
mamo3gr/arai60#6 (comment)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PEP 8でも同様の記述がなされていますね。

https://peps.python.org/pep-0008/

For sequences, (strings, lists, tuples), use the fact that empty sequences are false:

Correct:

    if not seq:
    if seq:

Wrong:

    if len(seq):
    if not len(seq):

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.

ありがとうございます。PEP 8のほうも確認させていただきました。何度か指摘されているので、まさにソフトウェアエンジニアの常識の典型例なのかなと感じています。

```
## Step 3
- 番兵を使って書いてみる。dictへのアクセスは結局その中にキーがあるかを確認する必要があるので、分岐の数自体は変わらないが、分岐より先にpopできるのが直感的でわかりやすい。

```python
class Solution:
def isValid(self, s: str) -> bool:
open_to_close = {'(' : ')',
'{' : '}',
'[' : ']'}
open_brackets = [None] # Put None as a sentinel
for bracket in s:
if bracket in open_to_close:
open_brackets.append(bracket)
else:
last = open_brackets.pop()
if not last or bracket != open_to_close[last]:
return False
return (len(open_brackets) == 1) # Check only the sentinel left
```

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

Choose a reason for hiding this comment

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

ありがとうございます!