Generate Parentheses – Solution & Complexity
Solution Walkthrough
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).
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.
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.
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.
5. Dry run
Trace n = 3 with 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 ["((()))","(()())","(())()","()(())","()()()"].
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.
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.
8. Final full solution and complexity
Backtracking with ( opens first, ) second explores only valid prefixes, so it emits every well-formed string exactly once in canonical order. The runtime is O(C_n * n) and the output dominates space at O(C_n * n), where C_n is the nth Catalan number; recursion itself uses O(n) extra stack space.