Generate Parentheses
Generate all combinations of well-formed parentheses. A parenthesis combination is well-formed if each opening parenthesis "(" is closed by a matching closing parenthesis ")" in the correct order.
For example, "()", "()()", and "((()))" are all combinations of well-formed parentheses, while ")(", "((" and "(()" are not.
Examples
n = 1 output: ["()"] n = 2 output: ["(())", "()()"] n = 3 output: ["((()))", "(()())", "(())()", "()(())", "()()()"] n = 4 output should contain: ["(((())))", "((()()))", "((())())", "((()))()", "(()(()))", "(()()())", "(()())()", "(())(())", "(())()()", "()((()))", "()(()())", "()(())()", "()()(())", "()()()()"]
The problem is to generate all combinations of well-formed parentheses given n pairs of parentheses. A combination is well-formed if every opening parenthesis has a corresponding closing parenthesis and they are properly nested.
Recursive Approach
The most common and intuitive way to solve this problem is by using recursion with backtracking. Here's a step-by-step breakdown of the approach:
-
Define the Problem:
- We need to build strings of length
2nusingnopening(andnclosing)parentheses. - At any point in the string, the number of closing parentheses should not exceed the number of opening parentheses to ensure the sequence is valid.
- We need to build strings of length
-
Recursive Function:
- We use a recursive helper function to build the strings character by character.
- The function tracks the remaining number of opening and closing parentheses that can still be added.
- It also maintains the current combination of the string being formed.
-
Base Case:
- If no more parentheses are remaining to add (both
remaining_openandremaining_closeare zero), the current combination is a valid sequence and is added to the result list.
- If no more parentheses are remaining to add (both
-
Recursive Case:
- Add an opening parenthesis
(if there are any remaining and recursively call the function with one less opening parenthesis. - Add a closing parenthesis
)if the number of remaining closing parentheses is greater than the remaining opening parentheses and recursively call the function with one less closing parenthesis.
- Add an opening parenthesis
-
Pruning Invalid Paths:
- If at any point the number of closing parentheses left is less than the number of opening parentheses left, it means the current sequence cannot be completed to a valid sequence, so we stop exploring that path.
Implementation Steps
-
Initialize:
- Create a result list to store all valid sequences.
- Call the recursive helper function with initial values (
nopening andnclosing parentheses).
-
Recursive Helper Function:
- Track the number of remaining opening and closing parentheses.
- Track the current combination being formed.
- Append valid combinations to the result list when the base case is reached.
-
Backtrack:
- After adding an opening or closing parenthesis, remove it (backtrack) before trying the next possibility. This ensures that we explore all possible valid combinations.
Example
Let's consider n = 3:
- Start with an empty combination
"",3opening, and3closing parentheses. - Add an opening parenthesis:
"(",2opening, and3closing. - Continue adding opening parentheses until you can no longer add without violating the rules.
- Then add closing parentheses and ensure that at no point the closing parentheses exceed the opening ones.
- Once you form a valid combination like
"((()))", add it to the result list. - Backtrack and explore other combinations.
Solution
def create_valid_string(remaining_open, remaining_close, combination, ans):
if remaining_open == 0 and remaining_close == 0:
ans.append(combination)
return
if remaining_open > remaining_close:
return
if remaining_open > 0:
create_valid_string(remaining_open - 1, remaining_close, combination + '(', ans)
if remaining_close > 0:
create_valid_string(remaining_open, remaining_close - 1, combination + ')', ans)
def generate_parentheses(n):
ans = []
if n == 0:
return ans
create_valid_string(n, n, '', ans)
return ansTime Complexity: The time complexity of this solution is . This is because each position in the string can either be an opening or closing parenthesis, and we need to generate all possible sequences of length .
Space Complexity: The space complexity of the solution is which simplifies to . This is because:
- The recursion depth is in the worst case (each recursive call adds either an opening or a closing parenthesis).
- The
combinationstring being formed is of length .
In this mock interview video, Aman (Google SWE) answers the interview question, "Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses."
# O(n) time from typing import List def generate_parentheses(n: int): res = [] def generate(buf, opened, closed): if len(buf) == 2 * n: if n != 0: res.append(buf) return if opened < n: generate( buf + "(", opened + 1, closed) if closed < opened: generate(buf + ")", opened, closed + 1) generate("", 0, 0) return res # debug your code below print(generate_parentheses(1))