-
Notifications
You must be signed in to change notification settings - Fork 0
Solved Arai60/22. Generate Parentheses #52
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,131 @@ | ||
| ## Step 1. Initial Solution | ||
|
|
||
| - 再帰的にやれば行けそう | ||
| - 前のやつの全体を囲うか()を前後につけるか | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| if n == 1: | ||
| return ["()"] | ||
| parentheses = set() | ||
| for parenthesis in self.generateParenthesis(n-1): | ||
| parentheses.add("".join(["(", parenthesis, ")"])) | ||
| parentheses.add("".join(["()", parenthesis])) | ||
| parentheses.add("".join([parenthesis, "()"])) | ||
| return list(parentheses) | ||
| ``` | ||
|
|
||
| - と思ったが(())(())のような部分的に囲むやつが考慮できていないので失敗 | ||
|
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. こういう風にしたいならば、はじめの括弧と対応するやつは必ずあるはずなので、
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. どういう実装をイメージされているんでしょうか? |
||
| - Stackで(の個数と)の個数を保持しながら処理していく方針に変更 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| parentheses = set() | ||
| parenthesis_opened_closed = [("", 0, 0)] | ||
| while parenthesis_opened_closed: | ||
| parenthesis, opened, closed = parenthesis_opened_closed.pop() | ||
| if opened == n: | ||
| new_parenthesis = parenthesis + (opened - closed) * ")" | ||
| if new_parenthesis not in parentheses: | ||
| parentheses.add(new_parenthesis) | ||
| continue | ||
| parenthesis += "(" | ||
| opened += 1 | ||
| for i in range(opened - closed + 1): | ||
| parenthesis_opened_closed.append((parenthesis + i * ")", opened, closed + i)) | ||
|
|
||
| return list(parentheses) | ||
| ``` | ||
|
|
||
| - あまり直感的ではないように感じたので(の数ごとに階層を区切って処理してみる | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| parentheses = [] | ||
| parentheses_and_openings = [("", 0)] | ||
| for opened in range(1, n + 1): | ||
| new_parentheses_and_openings = [] | ||
| for parenthesis, opening in parentheses_and_openings: | ||
| parenthesis += "(" | ||
| opening += 1 | ||
| if opened == n: | ||
| parentheses.append(parenthesis + opening * ")") | ||
| continue | ||
| for closing in range(opening + 1): | ||
| new_parentheses_and_openings.append((parenthesis + closing * ")", opening - closing)) | ||
| parentheses_and_openings = new_parentheses_and_openings | ||
| return parentheses | ||
| ``` | ||
|
|
||
|
|
||
| ### Complexity Analysis | ||
|
|
||
| - 時間計算量:O(n^n) | ||
| - 各層の計算量が<2k C k | ||
| - 2k C k < k^k なので大体このくらい? | ||
| - 空間計算量:O(n^n) | ||
|
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. これはちょっと大きすぎる見積もりです。
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. ですね |
||
|
|
||
| ## Step 2. Alternatives | ||
|
|
||
| - https://github.com/akmhmgc/arai60/pull/47/files#diff-49770f8b73d94c3a97c07766ce83932c7e9fc1168820a224bd14923bdfd5c876R10 | ||
| - (の追加と)の追加を各ループで行う方法 | ||
| - 確かにこの方法は分かりやすい | ||
| - popしてから次の分岐に行くから同じインスタンスを参照し続けられてメモリ効率も良い | ||
| - https://github.com/shintaro1993/arai60/pull/57/files#r2485774505 | ||
| - こちらでも同じことが言われていた | ||
| - https://github.com/shintaro1993/arai60/pull/57/files#diff-6c927ad20d197fb3d8c10182f5287498c084aca20e6c323cc144aa0ac3cbf4daR10 | ||
| - 全体的に自分のように各作業者がfor文を回してstackに乗せるような方法は少なそう | ||
| - 一つずつstackしていく方が分かりやすいのか? | ||
| - https://github.com/fhiyo/leetcode/pull/53/files#diff-9ca14f2eb9507a65f01cd60a9947537f09b5daeede1ef28ee1d790d8d76adb56R11 | ||
| - カタラン数なるものがあるらしい | ||
| - 2n C n / (n + 1)なので今回の計算量は(n+1) x Cnと書けそう | ||
| - スターリングの公式を使うと $n! = \sqrt{2 \pi n}(\frac{n}{e})^n$なので | ||
|
|
||
| $$ | ||
| _{2n}C_n = \frac{1}{\sqrt{\pi n}} 2^{2n} | ||
| $$ | ||
|
|
||
| - よって今回の計算量はO(n^(-1/2) *4^n)と書けそう | ||
| - https://github.com/fhiyo/leetcode/pull/53/files#diff-9ca14f2eb9507a65f01cd60a9947537f09b5daeede1ef28ee1d790d8d76adb56R257 | ||
| - generatorを使って作り上げていく方法 | ||
| - 他にもcacheを使うかとのトレードオフも判断していて参考になる | ||
|
|
||
| ## Step 3. Final Solution | ||
|
|
||
| - 一つずつStack | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| paren_opened_closed = [('', 0, 0)] | ||
| parens = [] | ||
| while paren_opened_closed: | ||
| paren, opened, closed = paren_opened_closed.pop() | ||
| if opened == n: | ||
| parens.append(paren + (opened - closed) * ')') | ||
| continue | ||
| paren_opened_closed.append((paren + '(', opened + 1, closed)) | ||
| if opened > closed: | ||
| paren_opened_closed.append((paren + ')', opened, closed + 1)) | ||
| return parens | ||
| ``` | ||
|
|
||
| - generatorを使う方法 | ||
| - どうやらLeetCode上ではあまり速くない上にメモリ効率も大きく変わらないよう | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def generateParenthesis(self, n: int) -> List[str]: | ||
| def generate_parens(opened: int, closed: int) -> Iterator[str]: | ||
| if opened == n: | ||
| yield ')' * (opened - closed) | ||
| return | ||
| if opened > closed: | ||
| yield from (')' + s for s in generate_parens(opened, closed + 1)) | ||
| yield from ('(' + s for s in generate_parens(opened + 1 , closed)) | ||
|
|
||
| return list(generate_parens(0, 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.
n == 0 で [""] のほうがいいでしょう。