22. Generate Parentheses - Detailed Explanation
1. Problem Statement
Description:
Given n pairs of parentheses, write a function to generate all combinations of well-formed (or valid) parentheses.
A combination is considered valid if:
- Every opening parenthesis '('has a corresponding closing parenthesis')'.
- The parentheses are correctly nested.
Examples:
- 
Example 1: - Input: n = 3
- Output:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
- Explanation: There are five distinct ways to arrange 3 pairs of well-formed parentheses.
 
- Input: 
- 
Example 2: - Input: n = 1
- Output: ["()"]
- Explanation: With one pair, the only valid combination is "()".
 
- Input: 
- 
Example 3: - Input: n = 2
- Output: ["(())", "()()"]
- Explanation: Two pairs can be arranged as nested parentheses or side by side.
 
- Input: 
Constraints:
- (1 \leq n \leq 8) (or similar, depending on the problem specification)
- The output order does not matter.
Hints
- 
Hint 1: 
 Think about the decision process for adding parentheses. At every step, decide whether to insert an opening or a closing parenthesis, while ensuring the sequence remains valid.
- 
Hint 2: 
 Use backtracking to explore all possible combinations. Track the number of opening and closing parentheses used. You can add an opening parenthesis if you haven’t reached n; you can add a closing parenthesis only if it would not lead to an invalid state (i.e., you have more openings than closings so far).
Approaches
Approach 1: Backtracking
Explanation
The backtracking approach is the most intuitive for this problem. The idea is to build the string character by character and backtrack when a decision leads to an invalid or complete solution.
How It Works:
- 
Initialization: 
 Start with an empty string and two counters:open(for'(') andclose(for')'). Initially, both are zero.
- 
Decision Making: - Add '('if:
 The number of opening parentheses used so far is less than n.
- Add ')'if:
 The number of closing parentheses used is less than the number of opening ones (to maintain validity).
 
- Add 
- 
Termination: 
 When the length of the string equals2 * n, you have a complete, well-formed combination. Add it to the results list.
- 
Backtracking: 
 Recursively build the string, and once a branch completes (or cannot be extended), backtrack to explore other possibilities.
Pseudocode
function backtrack(currentString, open, close, n, result):
    if length(currentString) == 2 * n:
        result.add(currentString)
        return
    if open < n:
        backtrack(currentString + "(", open + 1, close, n, result)
    if close < open:
        backtrack(currentString + ")", open, close + 1, n, result)
Visual Example (n = 3)
Imagine the recursion tree:
                ""
             /      \
           "("      (invalid branch if starting with ")")
           /  \
         "(("   "()"
         /  \    \
    "((("  "(()"  "()("
     ...    ...   ...
- At each node, choices are made based on the counts.
- Only when the string length reaches 6 (i.e., 2*n) is the string added to the results.
Code Examples
Python Code:
Java Code:
Approach 2: Dynamic Programming (Alternative)
Explanation
Dynamic Programming (DP) leverages the insight that the solution for n pairs of parentheses can be constructed from the solutions of fewer pairs. The recurrence relation is based on the idea that a valid combination can be formed by:
- Wrapping a valid combination for i pairs inside a new pair of parentheses, and then
- Concatenating it with a valid combination for n - 1 - i pairs.
The recurrence: [ \text{dp}[n] = \bigcup_{i=0}^{n-1} \{ "(" + x + ")" + y \;|\; x \in \text{dp}[i],\ y \in \text{dp}[n-1-i] \}]`
with base case dp[0] = [""].
This method is more advanced and might be less intuitive than backtracking, but it reinforces the concept of using smaller subproblems to build up to the solution.
Complexity
- Time Complexity:
 The number of valid combinations is the nth Catalan number (C(n) \approx \frac{4^n}{n^{3/2} \sqrt{\pi}}). The DP approach needs to generate all combinations, so the time complexity is proportional to the number of combinations.
- Space Complexity:
 O(4^n / n^(3/2)) for storing all the combinations.
Note: Backtracking is generally preferred for its clarity and lower overhead in this problem.
Complexity Analysis
Backtracking Approach:
- 
Time Complexity: 
 O(4^n / √n) – This is the nth Catalan number, which approximates the number of valid combinations.
- 
Space Complexity: 
 O(4^n / √n) for the output storage and O(n) for the recursion call stack.
Dynamic Programming Approach:
- 
Time Complexity: 
 Also proportional to the nth Catalan number due to the number of valid combinations being generated.
- 
Space Complexity: 
 Similar storage requirements for output plus additional DP array storage.
Common Mistakes and Edge Cases
Common Mistakes
- 
Incorrect Base Case: 
 Not handling the condition when n = 0 or not properly ending the recursion when the current string reaches the length (2 \times n).
- 
Improper Decision Checks: 
 Adding a closing parenthesis without ensuring that it won’t make the string invalid (i.e., having more')'than'('at any point).
- 
Overcomplicating the Recursion: 
 Including redundant conditions or not pruning the recursion tree when a branch can no longer produce a valid sequence.
Edge Cases
- 
n = 0: 
 Some definitions might return an empty list or a list containing an empty string[""].
- 
n = 1: 
 Only one valid combination exists:"()".
Alternative Variations and Related Problems
Variations
- 
Generate All Combinations with Different Symbols: 
 Instead of parentheses, you might be asked to generate combinations of different paired symbols (e.g.,{},[]).
- 
Return Count Instead of List: 
 Sometimes, you might be asked only for the count of valid combinations rather than generating each one.
Related Problems for Further Practice
- 
Valid Parentheses: 
 Check if a given string containing parentheses is valid.
- 
Longest Valid Parentheses: 
 Find the longest substring of valid parentheses in a given string.
- 
Remove Invalid Parentheses: 
 Remove the minimum number of invalid parentheses in order to make the input string valid.
- 
Binary Tree Paths: 
 Generate all root-to-leaf paths in a binary tree (similar recursive/backtracking approach).
GET YOUR FREE
Coding Questions Catalog
$197

$78
$78