The problem. Given n, return every string of n pairs of parentheses that is well-formed — each ) closes an earlier ( and every ( is closed — in any order.
n = 1 -> ["()"]
n = 2 -> ["(())", "()()"]
n = 3 -> ["((()))", "(()())", "(())()", "()(())", "()()()"]Generating all 2²ⁿ strings of brackets and keeping the valid ones works, but most of them are hopeless from an early point — anything starting with ), for example. Backtracking can prune those branches before they grow: build the string one bracket at a time and only allow a move that keeps the prefix fixable.
Two counts are enough. A ( is allowed while fewer than n have been used. A ) is allowed only while it has something to close — while close < open. With those rules every prefix stays valid, so every string that reaches length 2n is an answer, and nothing needs checking at the end.
function generateParenthesis(n) { const result = []; const valid = (s) => { let balance = 0; for (const ch of s) { balance += ch === "(" ? 1 : -1; if (balance < 0) return false; // a ')' with nothing to close } return balance === 0; }; const all = (s) => { // every string of '(' and ')' of length 2n if (s.length === 2 * n) { if (valid(s)) result.push(s); return; } all(s + "("); all(s + ")"); }; all(""); return result;}Time O(2²ⁿ · n), space O(n) beyond the output. For n = 8 that's 65,536 strings to build and check, to keep 1,430.
'(' while some are left, ')' only to close one: every finished string is valid.
function generateParenthesis(n) { const result = []; const path = []; const build = (open, close) => { // how many '(' and ')' are used so far if (path.length === 2 * n) { result.push(path.join("")); return; } if (open < n) { // a '(' is allowed while some are left path.push("("); build(open + 1, close); path.pop(); } if (close < open) { // a ')' only if it closes something path.push(")"); build(open, close + 1); path.pop(); } }; build(0, 0); return result;}Time O(4ⁿ / √n), space O(n) beyond the output. The number of answers is the n-th Catalan number, about 4ⁿ / (n^1.5 · √π), and since no branch dead-ends, the work is that number times the length 2n.
The lesson of this problem is pruning: the rules about when a choice is allowed cut the search down to exactly the answers.
"()".")("-style prefixes and produces invalid strings.