Generate Parentheses – Solution & Complexity
Solution Walkthrough
Step 1: Understand the search tree
- Every answer is a length-
2nstring built one character at a time. - A prefix is only worth continuing if it can still become valid: you can never close more parentheses than you have opened, and you can never open more than
n. - The required output order comes naturally if every recursive call tries
(before).
- Every answer is a length-
Step 2: Start from a brute-force baseline
- A direct baseline is to generate every length-
2nstring of(and), then keep only the balanced ones. - This is correct and still respects the required order if you branch to
(before), but it wastes time exploring obviously impossible prefixes.
- A direct baseline is to generate every length-
Step 3: Prune invalid prefixes early
- Instead of generating bad strings and rejecting them later, track how many opens and closes you have used so far.
- You may add
(only whileopen_count < n, and you may add)only whileclose_count < open_count. - Those two rules guarantee every recursive prefix can still lead to a valid answer.
Step 4: Optimal backtracking solution
- This DFS builds only valid prefixes and automatically emits answers in the required canonical order because every call tries
(before). - Once the current string reaches length
2n, it is a complete answer.
- This DFS builds only valid prefixes and automatically emits answers in the required canonical order because every call tries
Step 5: Dry run
Trace
n = 3with the optimal recursion.- Start with
"", so the only legal move is(. - Repeatedly preferring
(first reaches"((()", then"((())", then"((()))", which becomes the first answer. - Backtrack one step at a time to the nearest prefix that still allows a different valid choice, producing
"(()())", then"(())()", then"()(())", then"()()()".
Because every branch tries
(before), the results appear as["((()))","(()())","(())()","()(())","()()()"].- Start with
Step 6: Common mistakes and follow-ups
- Appending
)whenclose_count == open_count, which creates an invalid prefix immediately. - Forgetting to undo the last append before exploring the sibling branch.
- Returning a set or sorting afterward can hide bugs in the required canonical order.
- Follow-up: count combinations with Catalan DP when you need only the number, not the actual strings.
- Appending
Step 7: Edge cases to test mentally
n = 0should return[""], not[], because there is one valid empty construction.n = 1returns exactly["()"].- Larger
nvalues explode in output size, so the algorithm should avoid generating invalid branches at all.
Step 8: Final full solution and complexity
Backtracking with
( opens first, ) secondexplores only valid prefixes, so it emits every well-formed string exactly once in canonical order. The runtime isO(C_n * n)and the output dominates space atO(C_n * n), whereC_nis the nth Catalan number; recursion itself usesO(n)extra stack space.