Given an integer n
, write a function to generate all possible and valid combinations of parentheses, where n
represents the number of pairs of parentheses.
Example 1:
n = 3
["((()))", "(()())", "(())()", "()(())", "()()()"]
Example 2:
n = 1
["()"]
Clarifications:
n
is less than 1? (Clarify that n
will always be greater or equal to 1 based on constraints).Can you write an algorithm that efficiently generates all valid combinations of parentheses for a given n
?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to generating parentheses is like trying every single combination of open and close parentheses until you find the valid ones. It's an exhaustive search where we explore all possibilities, regardless of whether they make sense at first.
Here's how the algorithm would work step-by-step:
def generate_parentheses_brute_force(number):
def generate_all_combinations(current_string, number):
if len(current_string) == 2 * number:
return [current_string]
combinations = []
combinations.extend(generate_all_combinations(current_string + '(', number))
combinations.extend(generate_all_combinations(current_string + ')', number))
return combinations
def is_valid(parentheses_string):
balance = 0
for character in parentheses_string:
if character == '(':
balance += 1
else:
balance -= 1
# If balance goes below zero, it is invalid
if balance < 0:
return False
# Check if balanced overall
return balance == 0
# Generate all possible combinations of parens
all_combinations = generate_all_combinations("", number)
valid_combinations = []
# Filter out the invalid ones
for combination in all_combinations:
if is_valid(combination):
valid_combinations.append(combination)
return valid_combinations
The best way to generate valid parentheses is to build them gradually, making sure we always have a balanced number of opening and closing parentheses. We add parentheses one at a time, carefully tracking how many opening parentheses we've used and how many we're allowed to use.
Here's how the algorithm would work step-by-step:
def generate_parentheses(number):
results = []
def backtrack(current_string, open_count, close_count):
# When the string is complete, add to results.
if len(current_string) == 2 * number:
results.append(current_string)
return
# Add open parenthesis if we haven't used all.
if open_count < number:
backtrack(current_string + '(', open_count + 1, close_count)
# Ensures that we are adding a valid closing parenthesis.
if close_count < open_count:
backtrack(current_string + ')', open_count, close_count + 1)
# Initiate the process.
backtrack('', 0, 0)
return results
Case | How to Handle |
---|---|
n = 0 | Return an empty list as there are no parentheses to generate. |
n = 1 | Return a list containing only '()'. |
Very large n (e.g., n > 20) | The solution's time and space complexity should be exponential, so very large n may cause stack overflow or excessive memory usage, potentially requiring a check on the input value to prevent issues. |
Negative n | Treat negative n as an invalid input and return an empty list or throw an exception. |
Non-integer input | Ensure the input is an integer; otherwise, raise a TypeError or return an empty list if the input is invalid. |
Recursion depth exceeding stack limit | For very large n, iterative solution can avoid stack overflow; else, optimize the recursive logic or use tail-call optimization if supported by the language. |
n is a floating-point number | Convert the floating-point number to an integer using floor or round to ensure a valid input. |
Memory constraints prevent storing all valid combinations | For extreme n, using a generator or streaming approach might mitigate memory overflow by not holding all combinations in memory at once. |