Framework Thinking - Neetcode 150 - Generate Parentheses
Here is solutions for Generate Parentheses.
1. Understand the problem
- Given an integer n, generate all combinations of n pairs of parentheses that are valid (well-formed).
Example:
n = 3 → ["((()))", "(()())", "(())()", "()(())", "()()()"] (order can differ)
2. Clarify constraints, asks 4 - 5 questions including edge cases.
- What is the range of n?
- In LeetCode, 1 <= n <= 8 is typical. We’ll assume n is small (like ≤ 10), so exponential solutions are acceptable.
- Do we care about the order of the output list?
- No specific order is required. Any order that contains all valid combinations is acceptable.
- Are there any invalid inputs like n <= 0?
- Usually constraints exclude them, but if n = 0, a reasonable answer is [””] (one empty string). For this problem we’ll focus on n >= 1.
- Can we use extra space / recursion?
- Yes. This is a classic backtracking problem; recursion + extra lists are fine.
- Is there any requirement about duplicates?
- No; duplicates won’t appear if we build strings in a structured way (like backtracking). If we use brute force, we must be careful not to generate duplicates, but usually we won’t.
3. Explore examples.
- Example 1: n = 1
All strings of length 2:
() → valid
Answer: ["()"]
- Example 2: n = 2
Answer: ["(())", "()()"]
- Example 3: n = 3
- ((()))
- (()())
- (())()
- ()(())
- ()()()
- Example 4: n = 0
Just empty string: [""]
4. Brainstorm 2 - 3 solutions, naive solution first and optimize later. Explain the key idea of each solution.
4.1. Naive Brute Force (Generate All Strings and Filter) - Time O(2^(2N) * N), Space O(2^(2N) * N)
-
All strings of length 2n made from ‘(‘ and ‘)’ are 2^(2n) possibilities.
-
For each string:
-
Check if it’s a valid parentheses string.
-
If valid, add to result.
-
-
Validity check:
-
’(‘ → balance += 1
-
’)’ → balance -= 1
-
If balance < 0 → invalid (more ‘)’ than ‘(‘ somewhere).
-
4.2. Backtracking with Counts (Optimal / Standard) - Time O(4^n / (n^(3/2)) * N), Space O(4^n / (n^(3/2)) * N)
Key Idea:
- Build the string only along valid paths:
Track:
- open_used: how many '(' used so far.
- close_used: how many ')' used so far.
Rules:
- We can always add '(' if open_used < n.
- We can add ')' only if close_used < open_used. (we can’t close more than we opened)
4.3. DP / Catalan (Conceptual)
S = "(" + A + ")" + B
-
A is some valid string with i pairs.
-
B is some valid string with n - 1 - i pairs.
-
For all i from 0 to n-1, combine all A in dp[i] with all B in dp[n-1-i].
5. Implement solutions.
5.1. Naive Solution - Time O(2^2n * n), Space O(2^2n * n)
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 res
-
Time: O(2^2n * n)
-
Space: O(2^2n * n)
5.2. Backtracking with Prunning - Time O(4^N/sqrt(n)), Space O(N)
Idea:
-
Backtrack ‘)’ after ‘(‘
-
Prunning invalid cases.
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 res
-
Time: O(4^N/sqrt(n))
-
Space: O(N)
5.3. Dynamic Programming - Time O(4^N/sqrt(n)), Space O(N)
class Solution:
def generateParenthesis(self, n):
res = [[] for _ in range(n+1)]
res[0] = [""]
for k in range(n + 1):
for i in range(k):
for left in res[i]:
for right in res[k-i-1]:
res[k].append("(" + left + ")" + right)
return res[-1]
-
Time: O(4^N/sqrt(n))
-
Space: O(N)
6. Dry run testcases.
Example 1: n = 3
| Step | Path | Open | Close | Decision | Result |
|---|---|---|---|---|---|
| 2 | "(" |
1 | 0 | Add '(' |
— |
| Step | Path | Open | Close | Decision | Result |
|---|---|---|---|---|---|
| 3 | "((" |
2 | 0 | Add '(' |
— |
| Step | Path | Open | Close | Decision | Result |
|---|---|---|---|---|---|
| 4 | "(((" |
3 | 0 | Add ')' |
— |
| 5 | "((()" |
3 | 1 | Add ')' |
— |
| 6 | "((())" |
3 | 2 | Add ')' |
— |
| 7 | "((()))" |
3 | 3 | ✅ Length = 6 → Add | "((()))" |
Backtrack to “((“ and Try ‘)’:
| Step | Path | Open | Close | Decision | Result |
|---|---|---|---|---|---|
| 8 | "((" |
2 | 0 | Add ')' |
— |
| 9 | "(()" |
2 | 1 | Add '(' |
— |
| 10 | "(()(" |
3 | 1 | Add ')' |
— |
| 11 | "(()()" |
3 | 2 | Add ')' |
— |
| 12 | "(()())" |
3 | 3 | ✅ Add | "(()())" |
December 6, 2025