Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Generate Parentheses in Python
Generating well-formed parentheses is a classic programming problem that involves creating all valid combinations of opening and closing parentheses for a given number n. For n=3, we need 3 opening and 3 closing parentheses arranged in valid patterns.
Problem Understanding
A valid parentheses combination follows these rules ?
- Equal number of opening '(' and closing ')' parentheses
- At any point, the number of closing parentheses should not exceed opening ones
- All opening parentheses must be properly closed
Solution Approach
We use a recursive backtracking approach with these steps ?
- Track the count of remaining opening and closing parentheses
- Add an opening parenthesis if we still have some left
- Add a closing parenthesis only if it doesn't exceed the opening ones
- When both counts reach zero, we have a valid combination
Implementation
def generate_parentheses(n):
"""
Generate all valid parentheses combinations for n pairs
"""
result = []
def backtrack(current, open_count, close_count):
# Base case: we've used all parentheses
if open_count == 0 and close_count == 0:
result.append(current)
return
# Add opening parenthesis if available
if open_count > 0:
backtrack(current + "(", open_count - 1, close_count)
# Add closing parenthesis if it doesn't exceed opening ones
if close_count > open_count:
backtrack(current + ")", open_count, close_count - 1)
backtrack("", n, n)
return result
# Test with n = 3
result = generate_parentheses(3)
for combo in result:
print(combo)
((())) (()()) (())() ()(()) ()()()
Step-by-Step Example
Let's trace through how the algorithm works for n=2 ?
def generate_parentheses_with_trace(n):
result = []
def backtrack(current, open_count, close_count, depth=0):
indent = " " * depth
print(f"{indent}Current: '{current}', Open: {open_count}, Close: {close_count}")
if open_count == 0 and close_count == 0:
result.append(current)
print(f"{indent}? Valid combination: '{current}'")
return
if open_count > 0:
print(f"{indent}? Adding '('")
backtrack(current + "(", open_count - 1, close_count, depth + 1)
if close_count > open_count:
print(f"{indent}? Adding ')'")
backtrack(current + ")", open_count, close_count - 1, depth + 1)
backtrack("", n, n)
return result
# Trace for n = 2
print("Tracing parentheses generation for n = 2:")
result = generate_parentheses_with_trace(2)
print(f"\nFinal result: {result}")
Tracing parentheses generation for n = 2:
Current: '', Open: 2, Close: 2
? Adding '('
Current: '(', Open: 1, Close: 2
? Adding '('
Current: '((', Open: 0, Close: 2
? Adding ')'
Current: '(()', Open: 0, Close: 1
? Adding ')'
Current: '(())', Open: 0, Close: 0
? Valid combination: '(())'
? Adding ')'
Current: '()', Open: 1, Close: 1
? Adding '('
Current: '()(', Open: 0, Close: 1
? Adding ')'
Current: '()()', Open: 0, Close: 0
? Valid combination: '()()'
Final result: ['(())', '()()']
Alternative Implementation
Here's a cleaner version using a class-based approach ?
class ParenthesesGenerator:
def generate(self, n):
self.result = []
self._generate_helper(n, n, "")
return self.result
def _generate_helper(self, open_remaining, close_remaining, current):
if open_remaining == 0 and close_remaining == 0:
self.result.append(current)
return
if open_remaining > 0:
self._generate_helper(open_remaining - 1, close_remaining, current + "(")
if close_remaining > open_remaining:
self._generate_helper(open_remaining, close_remaining - 1, current + ")")
# Test the class
generator = ParenthesesGenerator()
result = generator.generate(4)
print(f"Generated {len(result)} valid combinations for n=4:")
for i, combo in enumerate(result, 1):
print(f"{i:2}. {combo}")
Generated 14 valid combinations for n=4: 1. (((()))) 2. ((()())) 3. ((())()) 4. ((()))() 5. (()(())) 6. (()()()) 7. (()())() 8. (())(()) 9. (())()() 10. ()((())) 11. ()(()()) 12. ()(())() 13. ()()(()) 14. ()()()()
Time and Space Complexity
The algorithm has the following complexity characteristics ?
- Time Complexity: O(4^n / ?n) - This is the nth Catalan number
- Space Complexity: O(4^n / ?n) - For storing all valid combinations
- Recursion Depth: O(2n) - Maximum depth of recursive calls
Conclusion
The recursive backtracking approach efficiently generates all valid parentheses combinations by carefully tracking opening and closing counts. The key insight is ensuring closing parentheses never exceed opening ones at any point in the construction process.
