From 443c5d4f1e3783014d033b2a4cf1188227466066 Mon Sep 17 00:00:00 2001 From: tokuhirat <54652919+tokuhirat@users.noreply.github.com> Date: Sun, 17 Aug 2025 14:51:56 +0900 Subject: [PATCH] Create 22. Generate Parentheses.md --- .../22. Generate Parentheses.md | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 22. Generate Parentheses/22. Generate Parentheses.md diff --git a/22. Generate Parentheses/22. Generate Parentheses.md b/22. Generate Parentheses/22. Generate Parentheses.md new file mode 100644 index 0000000..e412a70 --- /dev/null +++ b/22. Generate Parentheses/22. Generate Parentheses.md @@ -0,0 +1,104 @@ +# 22. Generate Parentheses +## STEP1 +- 何も見ずに解いてみる +- 単に再帰で () を至るところに挿入することを考えたが、重複して生成するのを防ぐ必要があり、set で管理すればできる。 +```python +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + if n <= 0: + raise ValueError("n must be positive.") + if n == 1: + return ["()"] + + results = set() + for s in self.generateParenthesis(n - 1): + for i in range(len(s) + 1): + results.add(s[:i] + "()" + s[i:]) + return list(results) +``` + +- そもそも重複せずに発生する方法も書けるか? "(" の数と ")" の数を管理して書く。 +```python +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + if n <= 0: + raise ValueError("n must be positive.") + + results = [] + + def generate_helper(parentheses: str, num_open: int, num_close: int) -> None: + if num_open == 0 and num_close == 0: + results.append(parentheses) + return + + if num_open == num_close: + generate_helper(parentheses + "(", num_open - 1, num_close) + return + + if num_open > 0: + generate_helper(parentheses + "(", num_open - 1, num_close) + generate_helper(parentheses + ")", num_open, num_close - 1) + + generate_helper("", n, n) + return results +``` +- 上のコードは毎回新しい文字列を構築している。list を使って書き直す。 +- ついでに "(" の追加をまとめて書く。"(" が使える限りは必ず追加できる。"(" と ")" が同数の場合は ")" は追加できないので終了。 +```python +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + if n <= 0: + raise ValueError("n must be positive.") + + results = [] + + def generate_helper(parentheses: list[str], num_open: int, num_close: int) -> None: + if num_open == 0 and num_close == 0: + results.append("".join(parentheses)) + return + + if num_open > 0: + parentheses.append("(") + generate_helper(parentheses, num_open - 1, num_close) + parentheses.pop() + if num_open == num_close: + return + parentheses.append(")") + generate_helper(parentheses, num_open, num_close - 1) + parentheses.pop() + + generate_helper([""], n, n) + return results +``` +- 手元で実行時間を計測したところ (10000 回の平均)、n = 8 で、文字列に追記する場合が 0.43 ms, list に追加する場合が 0.48 ms で、文字列に追記しても遅いわけではなかった。理由として、短い文字列であること、CPythonの場合は最適化される場合があること、が考えられるところでしょうか。 + +## STEP2 +### プルリクやドキュメントを参照 +- https://github.com/olsen-blue/Arai60/pull/54/files + - generate_helper([""], n, n) として括弧が両方 0 になれば終了か、generate_helper([""], 0, 0) として括弧が両方 n になれば終了かでは、前者の方が関数の処理が n に依存していないのでよいのではと思った。 +- https://github.com/shining-ai/leetcode/blob/main/arai60/50-53_Greedy_Backtracking/53_22_Generate%20Parentheses/rework.py + - num_open > 0 で "(" 追加、num_open < num_close: で ")" 追加という書き方もわかりやすいですね。 +## STEP3 +### 3回ミスなく書く +```python +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + if n <= 0: + raise ValueError("n must be positive.") + + results = [] + + def generate_helper(parentheses: str, num_open: int, num_close: int) -> None: + if num_open == 0 and num_close == 0: + results.append(parentheses) + return + if num_open > 0: + generate_helper(parentheses + "(", num_open - 1, num_close) + if num_open < num_close: + generate_helper(parentheses + ")", num_open, num_close - 1) + + generate_helper("", n, n) + return results +``` + +3分,3分,2分で3回Accept