The Parentheses Factory
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- L4
- Asked in
- Citadel
Problem
A template engine checks its output by enumerating every legal bracket nesting it could emit. Given a non-negative integer n, return every well-formed string built from n pairs of parentheses, including the empty string when n is 0. Order the results so that, comparing them character by character, an open paren ranks before a close paren.
Building balanced brackets is an art form.
Example 1
Input:
n = 3
Output:
["((()))","(()())","(())()","()(())","()()()"]
Example 2
Input:
n = 1
Output:
["()"]
Worked solution and explanation
What this really is
Strip the costume off and this is a constrained string-enumeration problem: you are walking the tree of all open/close sequences and refusing to descend any branch that can never close cleanly. Anyone can generate every length-2n string and filter; the people who pass build only the valid ones by enforcing two invariants as they go. Get the close condition wrong and you emit ())( and friends, or you silently drop half the answers.
Walking the decision tree
Step 1: Start from nothing
An empty string with both counters at zero. Every recursive call appends exactly one character, so the depth of the recursion is the length of the string so far.
Step 2: Spend an open paren when you have one
If open_count < n you still have opens left to spend, so recurse with ( appended and open_count bumped. Trying this branch first is what produces the open-before-close ordering the prompt asks for: deeper-nested strings come out ahead of flatter ones.
Step 3: Close only what is already open
Only when close_count < open_count is there an unmatched ( sitting to the left waiting to be closed. This is the guard that keeps every prefix valid; without it you generate garbage like )(.
Step 4: Collect at the leaf
When the string hits length 2n, both counters have reached n and the string is guaranteed balanced, so record it and return. No final validity check is needed because you never built an invalid prefix.
The solution
def generate_parentheses(n: int) -> list:
result = []
def backtrack(current, open_count, close_count):
if len(current) == 2 * n:
result.append(current)
return
if open_count < n:
backtrack(current + '(', open_count + 1, close_count)
if close_count < open_count:
backtrack(current + ')', open_count, close_count + 1)
backtrack('', 0, 0)
return resultTrying the open branch before the close branch yields ascending order with '(' ranked before ')'.
Common follow-up questions
- How would you return only the kth valid string without building the rest? (Tests ranking/unranking over Catalan-number sequences.)
- What changes if you also allow square and curly brackets? (Tests extending the invariant to a stack of bracket types with nesting rules.)
- Can you produce them iteratively instead of recursively? (Tests converting the recursion to an explicit stack.)