Example 1
ready- Input
n = 1- Expected
[ "()" ]- Why
- one pair has only one valid arrangement
A closing parenthesis can't pay a debt that hasn't been opened yet. That one rule lets you reject bad strings long before they're finished.
For an integer n, build every string that uses exactly n opening parentheses and
n closing parentheses in a valid arrangement. A string is valid when every opening
parenthesis has a later closing partner and no prefix closes more pairs than it opens.
Return the valid strings in any order, with no duplicates.
1 <= n <= 8Hints
You can generate every length-2 × n string made from ( and ), then scan each one
with a balance counter. How many candidates does that create?
Track how many opening and closing parentheses you've placed. You may add ( while
the opening count is below n; when is adding ) safe?
Add a closing parenthesis only when close < open. Once both counts reach n, the
current path is a complete answer and needs no separate validity check.
Could you compute how many answers exist for a given n without constructing any of
the strings?
Visible cases
n = 1[
"()"
]n = 3[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]n = 2[
"(())",
"()()"
]Interview signal
Start with all 2^(2 × n) = 4ⁿ strings of the right length. A balance counter rises for
( and falls for ). Reject a candidate if the balance ever goes negative, and keep
it only if the final balance is zero.
from itertools import product
def generate_parenthesis(n: int) -> list[str]:
result: list[str] = []
for symbols in product("()", repeat=2 * n):
balance = 0
valid = True
for symbol in symbols:
balance += 1 if symbol == "(" else -1
if balance < 0:
valid = False
break
if valid and balance == 0:
result.append("".join(symbols))
return resultEach candidate may need a full scan. Time O(4ⁿ · n). Space O(n) auxiliary for one candidate, excluding the returned strings.
This is the backtracking pattern: extend one candidate, explore it, then undo the choice. The sharper move is to extend only prefixes that can still become valid.
Keep two counts:
( only while opened < n.) only while closed < opened.def generate_parenthesis(n: int) -> list[str]:
result: list[str] = []
path: list[str] = []
def search(opened: int, closed: int) -> None:
if opened == n and closed == n:
result.append("".join(path))
return
if opened < n:
path.append("(")
search(opened + 1, closed)
path.pop()
if closed < opened:
path.append(")")
search(opened, closed + 1)
path.pop()
search(0, 0)
return resultThe number of answers is the n-th Catalan number Cₙ, the count of valid balanced
arrangements with n pairs. Writing each length-2 × n answer costs O(n), so
time O(Cₙ · n). Space O(n) auxiliary for the path and call stack, excluding the
output.
The pattern's pruning rule is the heart of the solution: once a prefix closes too much, no future character can repair it, so that branch never deserves a recursive call.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
[ "()" ]