-
Notifications
You must be signed in to change notification settings - Fork 0
20 Valid Parentheses #6
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| ### Step 1 | ||
| - stackのカテゴリの問題であるというヒントもあり、すぐに方針は立った | ||
| - 実装も割とすぐにできた | ||
| - 他のArai60の問題はgolangで解いてきたが、golangでの文字列処理は面倒なのでPythonを使うことにした | ||
|
|
||
| ```Python3 | ||
| class Solution: | ||
| def isValid(self, s: str) -> bool: | ||
| brackets = { | ||
| ")": "(", | ||
| "}": "{", | ||
| "]": "[" | ||
| } | ||
| stack: List[str] = [] | ||
| for i in range(len(s)): | ||
| if s[i] in brackets.keys(): | ||
| if len(stack) == 0: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 好みの問題だと思いますが、以下のように条件文をひとつづきにするのも自然に感じます。 if len(stack) == 0 or stack.pop() != brackets[s[i]]:
return False |
||
| return False | ||
| c = stack.pop() | ||
| if brackets[s[i]] != c: | ||
| return False | ||
| else: | ||
| stack.append(s[i]) | ||
| return len(stack) == 0 | ||
| ``` | ||
|
|
||
| ### Step 2 | ||
| - コードを整えつつ、discordで先人達のコードも参考にした | ||
| - close_to_openのマップよりopen_to_closeを使っているコードを多く見たのでそちらを試してみる | ||
| - if文をネストさせずに済んだのでこっちの方が良いだろう | ||
| - Pythonの好きでない点として、同じことをやろうとしても選択肢が多すぎるという点を挙げられるが、今回もまさしくそう | ||
| - スタックを普通のリストを使って実現するか、deque()を使うか、LifoQueueを使うか、、 | ||
| - 下記コードのようにLifoQueueを使うと、宣言時にこれはスタックであるということをリスト名にstackという言葉を入れなくてもわかるのが利点。欠点としては、メソッドがput, getでスタックぽくない | ||
| - 逆にリストやdeque()を使うと、スタックであるということを別の方法(命名やコメント)で伝えないといけなかったり、誤ってスタックではしない動作をさせてしまう可能性があるのが難点 | ||
|
|
||
| ```Python3 | ||
| from queue import LifoQueue | ||
|
|
||
|
|
||
| class Solution: | ||
| def isValid(self, s: str) -> bool: | ||
| open_to_close = { | ||
| "(": ")", | ||
| "{": "}", | ||
| "[": "]" | ||
| } | ||
| open_brackets = LifoQueue() | ||
|
|
||
| for i in range(len(s)): | ||
| if s[i] in open_to_close: | ||
| open_brackets.put(s[i]) | ||
| continue | ||
| if open_brackets.empty(): | ||
| return False | ||
| c = open_brackets.get() | ||
| if s[i] != open_to_close[c]: | ||
| return False | ||
|
|
||
| return open_brackets.empty() | ||
| ``` | ||
|
|
||
| ### Step 3 | ||
| - `for i in range(len(s))`を`for c in s`に変えて、Pythonらしくシンプルさを追求した | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これ今回はどちらでもいいですが、例えばsがdeque等だった場合を考えると、ランダムアクセスがO(1)で出来ないので、場合によっては気をつけた方が良さそうです。 |
||
| - `if c in open_to_close.keys()`もより短く`if c in open_to_close`に変えた | ||
|
|
||
| ```Python3 | ||
| from queue import LifoQueue | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LifoQueueはスレッドセーフな設計になっていて、ロックを取得するためパフォーマンス面では劣りそうです。ユースケースによって使い分けるといいと思います。https://docs.python.org/3/library/queue.html |
||
|
|
||
|
|
||
|
Comment on lines
+68
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ここの空白は1行にした方がいいと思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PEP 8的には2行ですね。
|
||
| class Solution: | ||
| def isValid(self, s: str) -> bool: | ||
| open_to_close = { | ||
| "(": ")", | ||
| "{": "}", | ||
| "[": "]" | ||
| } | ||
| open_brackets = 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() | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| - goでも解いてみました | ||
|
|
||
| ```Go | ||
| func isValid(s string) bool { | ||
| openToClose := map[rune]rune{ | ||
| '(': ')', | ||
| '{': '}', | ||
| '[': ']', | ||
| } | ||
| openBracketsStack := []rune{} | ||
|
|
||
| for _, c := range s { | ||
| if _, exist := openToClose[c]; exist { | ||
| openBracketsStack = append(openBracketsStack, c) | ||
| continue | ||
| } | ||
|
|
||
| l := len(openBracketsStack) | ||
| if l == 0 { | ||
| return false | ||
| } | ||
|
|
||
| top := openBracketsStack[l-1] | ||
| openBracketsStack = openBracketsStack[:l-1] | ||
| if c != openToClose[top] { | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| return len(openBracketsStack) == 0 | ||
| } | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ### Step 4 | ||
| - step1~3ではスタックを自作する必要のあるGoを避けてPythonを使ったが、他の問題はGoで解いてきたのでGoでやることに。 | ||
| - スタックも自作した | ||
|
|
||
| ```Go | ||
| type runeStack []rune | ||
|
|
||
| func (s runeStack) Empty() bool { return len(s) == 0 } | ||
|
|
||
| func (s *runeStack) Push(r rune) { | ||
| *s = append(*s, r) | ||
| } | ||
|
|
||
| func (s *runeStack) Pop() (rune, error) { | ||
| l := len(*s) | ||
| if l == 0 { | ||
| return rune(0), errors.New("Empty Stack") | ||
| } | ||
|
|
||
| last := (*s)[l-1] | ||
| *s = (*s)[:l-1] | ||
| return last, nil | ||
| } | ||
|
|
||
| func isValid(s string) bool { | ||
| openToClose := map[rune]rune{ | ||
| '(': ')', | ||
| '{': '}', | ||
| '[': ']', | ||
| } | ||
| openBracketStack := &runeStack{} | ||
|
|
||
| for _, c := range s { | ||
| if _, exist := openToClose[c]; exist { | ||
| openBracketStack.Push(c) | ||
| continue | ||
| } | ||
|
|
||
| last, err := openBracketStack.Pop() | ||
| if err != nil || c != openToClose[last] { | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| return openBracketStack.Empty() | ||
| } | ||
| ``` | ||
|
|
||
| - ちなみにスタックを自作せずスライスを使うと下のようになる。 | ||
| - スタックを自作すると手間はかかるが、可読性は増すということを実感した | ||
|
|
||
| ```Go | ||
| func isValid(s string) bool { | ||
| openToClose := map[rune]rune{ | ||
| '(': ')', | ||
| '{': '}', | ||
| '[': ']', | ||
| } | ||
| openBracketStack := []rune{} | ||
|
|
||
| for _, c := range s { | ||
| if _, exist := openToClose[c]; exist { | ||
| openBracketStack = append(openBracketStack, c) | ||
| continue | ||
| } | ||
| l := len(openBracketStack) | ||
| if l == 0 { | ||
| return false | ||
| } | ||
| last := openBracketStack[l-1] | ||
| openBracketStack = openBracketStack[:l-1] | ||
| if c != openToClose[last] { | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| return len(openBracketStack) == 0 | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[質問]
Goに詳しくないので質問させてください
Goのどのような部分が文字列処理を面倒にしていると思いますか??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
goでは文字列に対してインデックスで一文字取得するとbyte型で、rangeでループするとrune型という別の型になります。
for i, c := range sとしてループの中でs[i]とcを出力すると、例えば'('の場合、どちらも41という出力結果になります。しかし、型が違うのでs[i] == cはエラーになってしまいます。一方、Pythonだとsもs[i]も同じstr型なので文字列の処理の際に余計なことを考えずに済むので今回はPythonを選びました。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
もう一つgoではなくpythonを選んだ大きな理由として、goにはスタックを自分で実装する必要があるからです。今回だとスタックからのpopを以下のようにやらないといけません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
以上二つの理由から今回はgoを避けました。というより、面接で同じ問題が出されてgoを選んだらその時点で知識とセンスを疑われるような気がしたことが理由です。
以前勉強会で、面接で使う言語はその会社で使っている言語と必ずしも同じでなくて良いと伺いましたが、与えられた問題に対してどの言語を選ぶかというセンスは見られているでしょうか。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
言語を切り替えられないこともありますし、何だと書きやすいという話をすれば十二分だと思いますね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほど〜
標準ライブラリにデータ構造が乏しいのはGoにGenericsがなかったのも関係してるんですかね
サードパーティのライブラリ見てるとinterfaceでデータ構造を抽象化してるみたいですね
こっちが主流になっちゃって標準ライブラリのサポートがないままって感じなんでしょうか
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
「サードパーティが主流になっちゃった」というより最初から標準で用意するつもりがなかったと思います。goはミニマリスト思考が大きなコンセプトになるので
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
G 社内であんまり困った記憶ないんですよね。ちょっと複雑なことをすると、RPC を飛ばすことになっていたかと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
理解の確認をさせてください
これって、ある程度複雑なデータ処理は他のサービスをcallして任せていたからGo側の標準ライブラリにデータ構造が乏しくても困らなかったってことであってますか??