🧠
Backtracking with Pruning (Count Open and Close)
💡 This approach improves efficiency by pruning invalid sequences early, only adding '(' if we still have some left, and ')' only if it won't unbalance the string.
Intuition
Build the string step-by-step, keeping track of how many '(' and ')' have been used. Only add '(' if we still have some left, and add ')' only if it won't lead to invalid sequence (i.e., close count < open count).
Algorithm
- Start with an empty string and counts of open and close parentheses used.
- If the string length is 2n, add it to results.
- If open count < n, add '(' and recurse.
- If close count < open count, add ')' and recurse.
💡 The key insight is pruning invalid sequences early by tracking counts, which drastically reduces the search space.
def generateParenthesis(n):
result = []
def backtrack(s, open_count, close_count):
if len(s) == 2 * n:
result.append(s)
return
if open_count < n:
backtrack(s + '(', open_count + 1, close_count)
if close_count < open_count:
backtrack(s + ')', open_count, close_count + 1)
backtrack('', 0, 0)
return result
# Example usage
if __name__ == '__main__':
print(generateParenthesis(3))
Line Notes
def backtrack(s, open_count, close_count):Recursive helper tracking counts and current string
if len(s) == 2 * n:Base case: full valid sequence generated
if open_count < n:Add '(' if we still have some left
if close_count < open_count:Add ')' only if it won't unbalance
import java.util.*;
public class GenerateParentheses {
public static List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
backtrack("", 0, 0, n, result);
return result;
}
private static void backtrack(String current, int open, int close, int max, List<String> result) {
if (current.length() == max * 2) {
result.add(current);
return;
}
if (open < max) backtrack(current + "(", open + 1, close, max, result);
if (close < open) backtrack(current + ")", open, close + 1, max, result);
}
public static void main(String[] args) {
System.out.println(generateParenthesis(3));
}
}
Line Notes
private static void backtrack(String current, int open, int close, int max, List<String> result)Helper with current string and counts
if (current.length() == max * 2)Base case: full valid sequence
if (open < max)Add '(' if possible
if (close < open)Add ')' only if valid
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void backtrack(string current, int open, int close, int max, vector<string> &result) {
if (current.size() == max * 2) {
result.push_back(current);
return;
}
if (open < max) backtrack(current + '(', open + 1, close, max, result);
if (close < open) backtrack(current + ')', open, close + 1, max, result);
}
vector<string> generateParenthesis(int n) {
vector<string> result;
backtrack("", 0, 0, n, result);
return result;
}
int main() {
int n = 3;
vector<string> res = generateParenthesis(n);
for (auto &s : res) cout << s << endl;
return 0;
}
Line Notes
void backtrack(string current, int open, int close, int max, vector<string> &result)Recursive helper with counts and current string
if (current.size() == max * 2)Base case: full valid sequence
if (open < max)Add '(' if available
if (close < open)Add ')' only if valid
function generateParenthesis(n) {
const result = [];
function backtrack(s, open, close) {
if (s.length === 2 * n) {
result.push(s);
return;
}
if (open < n) backtrack(s + '(', open + 1, close);
if (close < open) backtrack(s + ')', open, close + 1);
}
backtrack('', 0, 0);
return result;
}
console.log(generateParenthesis(3));
Line Notes
function backtrack(s, open, close)Helper tracking current string and counts
if (s.length === 2 * n)Base case: full valid sequence
if (open < n)Add '(' if possible
if (close < open)Add ')' only if valid
TimeO(4^n / sqrt(n))
SpaceO(4^n / sqrt(n))
Number of valid sequences is the nth Catalan number ~4^n / (n^(3/2)), and each sequence is length 2n.
💡 For n=3, this means about 5 sequences generated efficiently, much fewer than brute force.
Interview Verdict: Accepted / Standard solution to code in interviews
This is the canonical backtracking solution that balances clarity and efficiency.