You are given an integer n. Return all well-formed parentheses strings that you can generate with n pairs of parentheses.
Example 1:
Input: n = 1
Output: ["()"]Example 2:
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]You may return the answer in any order.
Constraints:
1 <= n <= 7
You should aim for a solution as good or better than O(4^n / sqrt(n)) time and O(n) space, where n is the number of parenthesis pairs in the string.
A brute force solution would be to generate all possible strings of size 2n and add only the valid strings. This would be an O(n * 2 ^ (2n)) solution. Can you think of a better way? Maybe you can use pruning to avoid generating invalid strings.
We can use backtracking with pruning. But what makes a string invalid? Can you think of a condition for this?
When the count of closing brackets exceeds the count of opening brackets, the string becomes invalid. Therefore, we can maintain two variables, open and close, to track the number of opening and closing brackets. We avoid exploring paths where close > open. Once the string length reaches 2n, we add it to the result.
Generate all strings of length 2n using only '(' and ')'.
Most will be invalid, so for each completed string we validate it:
balance (opens count).'(' increases balance, ')' decreases it.balance ever becomes negative, there are too many ) early, which is invalid.balance must be 0, meaning all opens are closed.s.len(s) == 2n, check if s is valid using the balance rule:'('.')'.class Solution:
def generateParenthesis(self, n: int) -> List[str]:
res = []
def valid(s: str):
open = 0
for c in s:
open += 1 if c == '(' else -1
if open < 0:
return False
return not open
def dfs(s: str):
if n * 2 == len(s):
if valid(s):
res.append(s)
return
dfs(s + '(')
dfs(s + ')')
dfs("")
return resInstead of generating all strings and then checking validity, we build only valid strings.
Key rules for valid parentheses:
'(' only if you still have openings left (open < n).')' only if it won't break validity (close < open).open == close == n.So at every step, we make safe choices only, which avoids invalid paths early.
open - number of '(' used.close - number of ')' used.open == close == n, add the built string to the result.open < n, add '(' and recurse.close < open, add ')' and recurse.class Solution:
def generateParenthesis(self, n: int) -> List[str]:
stack = []
res = []
def backtrack(openN, closedN):
if openN == closedN == n:
res.append("".join(stack))
return
if openN < n:
stack.append("(")
backtrack(openN + 1, closedN)
stack.pop()
if closedN < openN:
stack.append(")")
backtrack(openN, closedN + 1)
stack.pop()
backtrack(0, 0)
return resA valid parentheses string can be built from smaller valid strings.
Think of this pattern: ( left ) right
left is a valid parentheses string with i pairs.right is a valid parentheses string with k - i - 1 pairs.left with () guarantees balance.right keeps the string valid.So, every valid result for k pairs is formed by combining smaller answers.
dp[x] store all valid parentheses strings with x pairs.dp[0] = [""] (empty string).k from 1 to n:i from 0 to k-1."(" + dp[i] + ")" + dp[k - i - 1]dp[k].dp[n].The condition to add ) is close < open, not close < n. Adding a closing parenthesis is only valid when there are unmatched opening parentheses. Using close < n would generate invalid strings like ())(() where closing brackets appear before their matching opens.
When using a mutable structure like a list or StringBuilder to build the string, you must remove the last character after the recursive call returns. Forgetting to pop/remove leads to corrupted strings in subsequent branches. The immutable string concatenation approach avoids this issue but is less memory efficient.
The base case should check open == n && close == n, not just length == 2n. While both conditions are mathematically equivalent for valid paths, explicitly checking both counters makes the logic clearer and helps catch bugs where invalid strings might reach length 2n through incorrect branching conditions.