Hard · backtracking
Generate Parentheses
You already wrote one backtracker — All Permutations chose from n values and undid its choice. This one chooses between exactly two characters, but the counters that guard each branch (open < n, close < open) do the pruning a used[] array did before.
At a glanceRecurse over positions: place <code>'('</code> if <code>open < n</code>, place <code>')'</code> if <code>close < open</code>; at position 2n, print. Trying '(' first yields lexicographic order for free.
Problem
Input: One integer n (1 ≤ n ≤ 8).
Output: Every valid string of n pairs, one per line, in the order produced by trying '(' before ')' (lexicographic).
Samples:
| Input | Output |
|---|---|
2 | (()) |
1 | () |
For n = 3 there are 5 valid strings out of 2^6 = 64 raw combinations — the two counter rules throw away 59 of them without ever building them. That is pruning: rejecting a branch before walking it.
Your solution
Custom input for "Run my input"
Judging runs in your browser against hidden tests. A runaway loop is cut off after 3 seconds — still, make sure every loop has an exit. Your code is saved in this browser as you type.
Stuck? Hints
Hint 1 — Validity is two local rules
A prefix can grow into a valid string exactly when (1) it has used fewer than n opens, and (2) every ')' it contains is matched — which reduces to close < open at every step. Two integer counters carry both facts; no stack, no validation pass at the end. The rules check as you go, which is why the tree prunes itself.
Hint 2 — The base case prints the buffer
When pos == 2 * n the buffer is a complete string — and it is valid by construction, because the counters never allowed anything else. Print it with a newline and return. Notice there is no validation step anywhere: correctness came from the branching rules, not from a check.
Hint 3 — Order of the two attempts = output order
Inside the function, try '(' first and ')' second. Depth-first with that order visits the strings exactly in lexicographic order — the same free lunch as All Permutations. Swap the two branches and every line of your output reorders itself.
Solution (try it first!)
#include <iostream>
using namespace std;
int n;
char buf[20];
void generate(int pos, int open, int close) {
if (pos == 2 * n) {
for (int i = 0; i < pos; i++) cout << buf[i];
cout << endl;
return;
}
if (open < n) {
buf[pos] = '(';
generate(pos + 1, open + 1, close);
}
if (close < open) {
buf[pos] = ')';
generate(pos + 1, open, close + 1);
}
}
int main() {
cin >> n;
generate(0, 0, 0);
return 0;
}
This is backtracking with pruning in its purest form: the search space is 2^(2n) raw, the counters cut it to the Catalan number — about 4^n / n^1.5 — without a single wasted branch. The family is growing: choices from a set in All Permutations, choices under constraints here. Next relatives: subsets with a sum condition, N-queens, sudoku.
Deep dive
Why this works
Two counters encode the whole validity predicate: fewer than n opens used, and never more closes than opens. Branching under those guards means every leaf of the search tree is valid by construction — no post-validation, and the tree is pruned before walking (2^(2n) raw strings collapse to the Catalan number).
The cost
O(Catalan(n) × n) time — about 4^n / n^1.5 strings, each printed in O(n) — and O(n) depth of recursion. n = 8 gives 1430 strings; the raw 2^(2n) = 65536 would be tried only if you validated at the end instead of pruning on the way.
Where it goes wrong
- Loosening
close < opentoclose < nprints invalid strings — the guard is the whole algorithm. - Forgetting to print at
pos == 2n(or printing inside the branches) yields partial prefixes or duplicates. - Trying ')' first reorders the output; the judge compares sequences, so attempt order matters as much as validity.
Next step
Same skeleton, richer rules: choices from a set in All Permutations, choices under two counters here. The natural next branches: subsets with a sum target, N-queens.
Two things to remember
- Pruning = rejecting a branch before walking it; two counters suffice here.
- DFS attempt order defines output order — '(' before ')' gives lexicographic for free.
🐞 This version fails — open it and try
Checks close < n instead of close < open — invalid strings slip in
#include <iostream>
using namespace std;
int n;
char buf[20];
void generate(int pos, int open, int close) {
if (pos == 2 * n) {
for (int i = 0; i < pos; i++) cout << buf[i];
cout << endl;
return;
}
if (open < n) {
buf[pos] = '(';
generate(pos + 1, open + 1, close);
}
if (close < n) { // bug: should be close < open
buf[pos] = ')';
generate(pos + 1, open, close + 1);
}
}
int main() {
cin >> n;
generate(0, 0, 0);
return 0;
}