Browse curriculum

Generate Parentheses

Build only well-formed strings of n pairs, using two guards instead of generating and filtering.

Examples

Input:n = 3
Output:["((()))","(()())","(())()","()(())","()()()"]
Explain:

The five well-formed strings of three pairs — Catalan(3).

Input:n = 1
Output:["()"]
Explain:

One pair, one way to write it.

Problem Understanding

List every string that uses exactly n opening and n closing parentheses and is well formed, meaning no prefix ever closes more brackets than it has opened.

Example: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]

Algorithm Strategy

Instead of generating all 2²ⁿ strings and validating them, we can build only valid strings.

Rules:

  1. Open: We can add an open parenthesis ( if open_count < n.
  2. Close: We can add a closing parenthesis ) if close_count < open_count.

This ensures we never close more than we open (validity) and never exceed n (completeness).

Interactive Visualization

Every node is one call to backtrack(open, close). Its label is the bracket that call added, and the pair under it is opened, closed — the two counts the guards test. ( branches go left and ) branches go right.

A call with only one child is a guard that said no, and the figure stops on that check as a step of its own: no ( once all n are open, and no ) when there is nothing open to close. The bottom row is the answer, in the order the code returns it.

Dry Run

Tracing n = 2.

# Call Path What happens
1 backtrack(0, 0) "" 0 < 2: add ( → backtrack(1, 0)
2 backtrack(1, 0) ( 1 < 2: add ( → backtrack(2, 0)
3 backtrack(2, 0) (( 2 < 2 fails — no (. 0 < 2: add ) → backtrack(2, 1)
4 backtrack(2, 1) (() No (. 1 < 2: add ) → backtrack(2, 2)
5 backtrack(2, 2) (()) Length 4: record (()), return
6 backtrack(2, 1), then backtrack(2, 0) (( Pop ) twice — both return
7 backtrack(1, 0) ( Pop (. 0 < 1: add ) → backtrack(1, 1)
8 backtrack(1, 1) () 1 < 2: add ( → backtrack(2, 1)
9 backtrack(2, 1) ()( No (. 1 < 2: add ) → backtrack(2, 2)
10 backtrack(2, 2) ()() Length 4: record ()(), return
11 backtrack(1, 1) () Pop (. 1 < 1 fails — no ). Return
12 backtrack(0, 0) "" Pop (. 0 < 0 fails — no ). Return

Result: ["(())", "()()"] — every string was valid when it was built, so nothing was generated and thrown away.

Edge Cases & Common Mistakes

Watch out for these pitfalls:

  • The 'Random String' trap: A common brute force mistake is generating all 2²ⁿ strings of '(' and ')' and checking validity. That is O(n × 4ⁿ) work for only Catalan(n) answers. Backtracking is vastly superior.

  • Base Case Confusion: Remember the base case is when open == n and close == n (string length 2n). Don't stop just because you can't add more open brackets.

  • Strict Order: You can NEVER add a closing parenthesis if close >= open. This simple rule guarantees validity.

Solution

One algorithm in all six languages — the lines light up as the figure above steps.

Generate Parentheses Code
1var generateParenthesis = function(n) {
2 const result = [];
3 const path = [];
4
5 const backtrack = (openCount, closeCount) => {
6 if (path.length === 2 * n) {
7 result.push(path.join(''));
8 return;
9 }
10 if (openCount < n) {
11 path.push('(');
12 backtrack(openCount + 1, closeCount);
13 path.pop();
14 }
15 if (closeCount < openCount) {
16 path.push(')');
17 backtrack(openCount, closeCount + 1);
18 path.pop();
19 }
20 };
21
22 backtrack(0, 0);
23 return result;
24};

The approach, step by step

  1. Record at length 2n

    When the path has 2n characters, every pair is opened and closed: join it into a string and record it.

  2. Open if you can

    While fewer than n have been opened, add "(", recurse with open + 1, and pop it.

  3. Close if you can

    While fewer have been closed than opened, add ")", recurse with close + 1, and pop it.

Frequently asked questions

Why is close < open the only check a closing bracket needs?

A prefix is valid as long as it never closes more pairs than it has opened. Adding ")" only when close < open keeps that true at every step, and adding "(" only while open < n makes sure the string can still be finished.


Why not generate every string of brackets and filter the valid ones?

There are 2^(2n) strings of length 2n and only Catalan(n) of them are valid — 14 of 256 for n = 4. The guards never build an invalid prefix, so no work is thrown away.


How many strings are there for n pairs?

The nth Catalan number: 1, 2, 5, 14, 42 … for n = 1, 2, 3, 4, 5. It grows roughly as 4^n / (n√n), which is where the time complexity comes from.

Applying for software engineering roles? Free, no sign-up:

AI resume checker — match your resume to the job description