-
Notifications
You must be signed in to change notification settings - Fork 0
22. Generate Parenthesis.md #43
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,188 @@ | ||
| ### Step1 | ||
|
|
||
| - まずはバックトラック | ||
| - カタラン数のため、再帰の限界は大丈夫なはず? | ||
| - returnはなくても一応大丈夫だが、合ったほうが読み手に推理させず親切か | ||
|
|
||
| ```python | ||
|
|
||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| parenthesis = [] | ||
| parenthesis_length_all = 2 * n | ||
|
|
||
| def generate_parenthesis_after(open_count_so_far, close_count_so_far): | ||
| if parenthesis_length_all == open_count_so_far + close_count_so_far: | ||
| if open_count_so_far == close_count_so_far: | ||
| yield ''.join(parenthesis) | ||
| return | ||
| if open_count_so_far < n: | ||
| parenthesis.append('(') | ||
| yield from generate_parenthesis_after(open_count_so_far + 1, close_count_so_far) | ||
| parenthesis.pop() | ||
| if close_count_so_far < open_count_so_far: | ||
| parenthesis.append(')') | ||
| yield from generate_parenthesis_after(open_count_so_far, close_count_so_far + 1) | ||
| parenthesis.pop() | ||
|
|
||
| return list(generate_parenthesis_after(0, 0)) | ||
| ``` | ||
|
|
||
| - バックトラックよりこういう単純な再帰の方が好きかも | ||
| - parenthesisという変数があっちこっちで動くのはややわかりにくい | ||
| - 上は再帰に入る前に違反しないようにcheckしているが、違反した後にreturnしてみた。ややオーバーヘッドがあるかもだが、こっちの方がやや好み? | ||
| - yieldされる条件のif open_count_so_far == close_count_so_far:はなくてもいいが、入れたほうが読みやすいと思い入れた | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| parenthesis_length_all = 2 * n | ||
|
|
||
| def generate_parenthesis_after(open_count_so_far, close_count_so_far): | ||
| if open_count_so_far + close_count_so_far == parenthesis_length_all: | ||
| if open_count_so_far == close_count_so_far: | ||
| yield '' | ||
| return | ||
| if open_count_so_far > n: | ||
| return | ||
| if close_count_so_far > open_count_so_far: | ||
| return | ||
| for next_parenthesis in generate_parenthesis_after(open_count_so_far + 1, close_count_so_far): | ||
| yield '(' + next_parenthesis | ||
| for next_parenthesis in generate_parenthesis_after(open_count_so_far, close_count_so_far + 1): | ||
| yield ')' + next_parenthesis | ||
|
|
||
| return list(generate_parenthesis_after(0, 0)) | ||
| ``` | ||
|
|
||
| ## Step2 | ||
|
|
||
| https://github.com/fhiyo/leetcode/pull/53/files | ||
|
|
||
| - (, )は英語でleft, rightともいうのか。ただ、left, right1単語だけだと、今見てるindexよりleftかどうかとわからなくなりそう | ||
| - ( + ) * できるだけ を一つの単位として引き継ぐ方法もある | ||
| - L166のlengthだけの確認しばらく後に、L173~174の残りopenの確認があってOKと確認するのはやや戸惑った | ||
| - 下の自分のコードは、parenthesisを引数で回してもよかったかね。まあどちらでもいいかなあ | ||
| - for right_count_to_append in range(left_count_unclosed + 2): で+2がいきなり出てくるのはわかりにくいかもと思ったが、特に解決策はない | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| parenthesis = "" | ||
|
|
||
| def generate_parentheses_helper(left_count_unclosed, rest_right_count): | ||
|
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. unclosed_left_countのほうが意味がわかると思います
Owner
Author
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. 確かに修飾語は前にあったほうがわかりやすいですね |
||
| nonlocal parenthesis | ||
| if rest_right_count == 0 and left_count_unclosed == 0: | ||
| yield parenthesis | ||
| return | ||
| original_length = len(parenthesis) | ||
| if left_count_unclosed < rest_right_count: | ||
| for right_count_to_append in range(left_count_unclosed + 2): | ||
| parenthesis += '(' + ')' * right_count_to_append | ||
| yield from generate_parentheses_helper(left_count_unclosed + 1 - right_count_to_append, rest_right_count - right_count_to_append) | ||
| parenthesis = parenthesis[:original_length] | ||
|
|
||
| return list(generate_parentheses_helper(0, n)) | ||
| ``` | ||
|
|
||
| https://github.com/rossy0213/leetcode/pull/27/files | ||
|
|
||
| - バックトラックされる文字列をnonlocalではなく引数に入れているが、引数が多いと多いで管理が難しそう。ただnonlocalもそれはそれで微妙かも | ||
|
|
||
| https://github.com/rihib/leetcode/pull/11/files | ||
|
|
||
| - stackという変数で文字列を管理するのもちょっと変わった気もするが、まあアリなのかな | ||
|
|
||
| https://github.com/wf9a5m75/leetcode3/pull/2/files | ||
|
|
||
| - 少し変わったやり方だが、これはこれでアリかも? | ||
| - 「n個目まで見た時に有効なかっこ列である」ような最小のnについて場合わけしている、と解釈できる | ||
| - 下のコードは少しネストが深いかな。for inside_count in range(n):より下の部分を関数化するか迷ったが、流石にくどい? | ||
|
|
||
| ```python | ||
|
|
||
| def generator_cache(f): | ||
| cache = {} | ||
| kargs_mark = (object(),) | ||
|
|
||
| def copy_generator_for_cache_and_return(*args, **kargs): | ||
| key = args + kargs_mark + tuple(kargs.items()) | ||
|
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. kargs.items() 順序が入れ替わる可能性があるが、その場合でも本来同じものなのではないでしょうか。
Owner
Author
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 key not in cache: | ||
| cache[key] = f(*args, **kargs) | ||
| cache[key], result = tee(cache[key]) | ||
| return result | ||
|
|
||
| return copy_generator_for_cache_and_return | ||
|
|
||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
|
|
||
| @generator_cache | ||
| def generate_parenthesis_helper(n): | ||
| if n == 0: | ||
| yield "" | ||
| for inside_count in range(n): | ||
| for inside in generate_parenthesis_helper(inside_count): | ||
| for outside in generate_parenthesis_helper(n - 1 - inside_count): | ||
| yield '(' + inside + ')' + outside | ||
|
|
||
| return list(generate_parenthesis_helper(n)) | ||
| ``` | ||
|
|
||
| - cacheは呼び出し元に破壊されるリスクはある。なるほど。 | ||
| - 上の自分のコードの場合は、関数が呼ばれるたびに新たに内部の関数のオブジェクトが作られるから大丈夫 | ||
| - generatorをcacheする方法 | ||
|
|
||
| https://github.com/goto-untrapped/Arai60/pull/11/files | ||
|
|
||
| - 全部作ってから後でvalidか確認する方法もあり(ちょっと無駄だが) | ||
| - (の閉じてない数は、left_countではないような?(left_unclosed_count?) | ||
| - 個人的には2 * nをlength_to_makeとか変数定義した方がわかりやすく感じるが、好みの問題か | ||
|
|
||
| https://github.com/shining-ai/leetcode/pull/53/files | ||
|
|
||
| - remainの個数を辞書にして表現するStep1はわかりやすいと思った | ||
| - ループに直してみる | ||
|
|
||
| ```python | ||
|
|
||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| stack = [("", 0, 0)] | ||
| result = [] | ||
| while stack: | ||
| parenthesis, left_count, right_count = stack.pop() | ||
| if left_count == n and right_count == n: | ||
| result.append(parenthesis) | ||
| continue | ||
| if left_count < n: | ||
| stack.append((parenthesis + '(', left_count + 1, right_count)) | ||
| if left_count > right_count: | ||
| stack.append((parenthesis + ')', left_count, right_count + 1)) | ||
| return result | ||
| ``` | ||
|
|
||
| https://github.com/frinfo702/software-engineering-association/pull/10/files | ||
|
|
||
| - currentはあまり意味なさそう?backtrackはぎり許容できる関数名 | ||
|
|
||
| ### Step3 | ||
|
|
||
| - かっこ列について、やはり再帰の直前、直後でpopやappendしたり、nonlocalで管理するよりは、引数で管理するのがわかりやすい | ||
|
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. Generator 楽しいですが、オーソドックスにこれが一番でしょうね。 Generator のいいところとして、すべて使わないときに計算を省略できるとか中間のメモリーが軽くなることがあるなどはあるでしょう。 |
||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| result = [] | ||
| def generate_parenthesis_helper(parenthesis, left_count, right_count): | ||
| if left_count == n and right_count == n: | ||
| result.append(parenthesis) | ||
| return | ||
| if left_count < n: | ||
| generate_parenthesis_helper(parenthesis + '(', left_count + 1, right_count) | ||
| if right_count < left_count: | ||
| generate_parenthesis_helper(parenthesis + ')', left_count, right_count + 1) | ||
|
|
||
| generate_parenthesis_helper('', 0, 0) | ||
| return result | ||
| ``` | ||
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.
自分はopen closeを使いました