Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions problems/0022-generate-parentheses/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 0022. Generate Parentheses

[LeetCode Link](https://leetcode.com/problems/generate-parentheses/)

Difficulty: Medium
Topics: String, Dynamic Programming, Backtracking, Bracket Sequences
Acceptance Rate: 79.3%

## Hints

### Hint 1

You need to produce *every* valid string, not count them. Whenever a problem asks you to enumerate all combinations, think about building the answer one character at a time and exploring choices recursively.

### Hint 2

Use backtracking: at each position you can either place `(` or `)`. Instead of generating all `2^(2n)` strings and filtering, try to prune invalid branches *while* building. What information do you need to track to know whether a choice is still legal?

### Hint 3

Track two counters: `open` (how many `(` used) and `close` (how many `)` used).
- You may add `(` only if `open < n`.
- You may add `)` only if `close < open` (there is an unmatched `(` to close).

With these two rules, every completed string of length `2n` is automatically valid — no filtering needed.

## Approach

We build strings recursively with a shared byte buffer of length `2n`.

1. Start with an empty buffer, `open = 0`, `close = 0`.
2. If the buffer is full (`open + close == 2n`), record a copy of it as an answer.
3. Otherwise:
- If `open < n`, write `(` at the current position and recurse with `open + 1`.
- If `close < open`, write `)` at the current position and recurse with `close + 1`.
4. Because we overwrite the same position on each branch, no explicit "undo" step is needed.

**Why it works:** A parentheses string is well-formed iff every prefix has at least as many `(` as `)`, and the totals are equal. Rule `close < open` enforces the prefix condition; rule `open < n` plus the length `2n` forces the totals to be equal. Every branch we explore leads to at least one valid string, so we never waste work on dead ends.

**Example (n = 2):**

```
"" -> "(" -> "((" -> "(()" -> "(())"
-> "()" -> "()(" -> "()()"
```

Trying `(` before `)` at each step yields results in lexicographic order, matching the example output.

## Complexity Analysis

Time Complexity: O(4^n / √n) — the number of valid strings is the n-th Catalan number `C(n) ~ 4^n / (n^{3/2}·√π)`, and each takes O(n) to copy into the result.
Space Complexity: O(n) auxiliary (recursion depth and buffer of size `2n`), excluding the O(4^n / √n) output.

## Edge Cases

- **n = 1:** The smallest input; only `"()"` is valid. Make sure the base case triggers correctly.
- **Never closing before opening:** Strings like `")("` must never be generated — guarded by `close < open`.
- **Too many opens:** Strings like `"((("` for n = 2 must be cut off — guarded by `open < n`.
- **Larger n (up to 8):** Output grows to 1430 strings; the pruned backtracking handles this easily, but naive generate-and-filter (`2^16` strings) is wasteful.
- **Buffer reuse:** When reusing a byte slice, convert to `string` at the leaf so each result is an independent copy.
44 changes: 44 additions & 0 deletions problems/0022-generate-parentheses/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
number: "0022"
frontend_id: "22"
title: "Generate Parentheses"
slug: "generate-parentheses"
difficulty: "Medium"
topics:
- "String"
- "Dynamic Programming"
- "Backtracking"
- "Bracket Sequences"
acceptance_rate: 7935.0
is_premium: false
created_at: "2026-10-02T05:58:06.797565+00:00"
fetched_at: "2026-10-02T05:58:06.797565+00:00"
link: "https://leetcode.com/problems/generate-parentheses/"
date: "2026-10-02"
---

# 0022. Generate Parentheses

Given `n` pairs of parentheses, write a function to _generate all combinations of well-formed parentheses_.



**Example 1:**


**Input:** n = 3
**Output:** ["((()))","(()())","(())()","()(())","()()()"]


**Example 2:**


**Input:** n = 1
**Output:** ["()"]




**Constraints:**

* `1 <= n <= 8`
30 changes: 30 additions & 0 deletions problems/0022-generate-parentheses/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

// Approach: backtracking with two counters.
// Place '(' while open < n, and ')' while close < open. Every string of
// length 2n built under these rules is well-formed, so no filtering is needed.
// Time: O(4^n / sqrt(n)), Space: O(n) auxiliary.
func generateParenthesis(n int) []string {
result := []string{}
buf := make([]byte, 2*n)

var backtrack func(open, close int)
backtrack = func(open, close int) {
pos := open + close
if pos == 2*n {
result = append(result, string(buf))
return
}
if open < n {
buf[pos] = '('
backtrack(open+1, close)
}
if close < open {
buf[pos] = ')'
backtrack(open, close+1)
}
}

backtrack(0, 0)
return result
}
77 changes: 77 additions & 0 deletions problems/0022-generate-parentheses/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"sort"
"testing"
)

func isWellFormed(s string) bool {
balance := 0
for _, c := range s {
if c == '(' {
balance++
} else {
balance--
}
if balance < 0 {
return false
}
}
return balance == 0
}

func TestGenerateParenthesis(t *testing.T) {
tests := []struct {
name string
n int
expected []string
}{
{"example 1: n = 3", 3, []string{"((()))", "(()())", "(())()", "()(())", "()()()"}},
{"example 2: n = 1", 1, []string{"()"}},
{"edge case: n = 2", 2, []string{"(())", "()()"}},
{"edge case: n = 4", 4, []string{
"(((())))", "((()()))", "((())())", "((()))()", "(()(()))",
"(()()())", "(()())()", "(())(())", "(())()()", "()((()))",
"()(()())", "()(())()", "()()(())", "()()()()",
}},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := generateParenthesis(tt.n)
got := append([]string(nil), result...)
want := append([]string(nil), tt.expected...)
sort.Strings(got)
sort.Strings(want)
if len(got) != len(want) {
t.Fatalf("got %d results %v, want %d results %v", len(got), got, len(want), want)
}
for i := range got {
if got[i] != want[i] {
t.Errorf("got %v, want %v", got, want)
break
}
}
})
}
}

func TestGenerateParenthesisCatalanCount(t *testing.T) {
catalan := []int{1, 1, 2, 5, 14, 42, 132, 429, 1430}
for n := 1; n <= 8; n++ {
result := generateParenthesis(n)
if len(result) != catalan[n] {
t.Errorf("n=%d: got %d results, want %d", n, len(result), catalan[n])
}
seen := make(map[string]bool)
for _, s := range result {
if len(s) != 2*n || !isWellFormed(s) {
t.Errorf("n=%d: invalid string %q", n, s)
}
if seen[s] {
t.Errorf("n=%d: duplicate string %q", n, s)
}
seen[s] = true
}
}
}