当前位置: 首页 > news >正文

【LeetCode】22. 括号生成

文章目录

  • 22. 括号生成
    • 📝 题目描述
    • 💡 解题思路(仿照 96:结构 + 计数)
      • 回溯核心思想(合法性剪枝)
      • 生成式动态规划(结构拼接)
      • 数量验证(卡塔兰数)
    • 📊 复杂度分析
    • 🎯 示例(n=3)
    • 💻 运行方式
    • 🧪 预期输出(节选)
    • 🔎 相关题目
    • 完整题解代码

22. 括号生成

📝 题目描述

数字 n 代表生成括号的对数,请你设计一个函数,用于生成所有可能且有效的括号组合。

  • 输入:n(1 <= n <= 8)
  • 输出:所有有效括号字符串的数组,如 n=3 → [“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]

💡 解题思路(仿照 96:结构 + 计数)

这是一道典型的卡塔兰结构题。常见三种角度:

  • 回溯(合法性剪枝)— 推荐,用状态约束生成所有解。
  • 生成式动态规划(按结构拼接)— 利用“(A)B”的结构划分构造所有解。
  • 卡塔兰数计数— 只用于验证数量是否正确,不生成解。

回溯核心思想(合法性剪枝)

  • 任何时刻放置 ‘)’ 不能超过 ‘(’ 的数量;
  • ‘(’ 的数量不超过 n,‘)’ 的数量不超过 n;
  • 当 leftrightn 时得到一个有效解。
flowchart LRS([start]) --> A{left < n?}A -- 是 --> P[加 "("] --> A2{right < left?}A2 -- 是 --> Q[加 ")"] --> A3{完成?}A2 -- 否 --> A3A3 -- 否 --> AA -- 否 --> B{right < left?}B -- 是 --> R[加 ")"] --> B2{完成?}B -- 否 --> E([剪枝])B2 -- 否 --> AA3 -- 是 --> T([记录答案])B2 -- 是 --> T

生成式动态规划(结构拼接)

  • 定义:dp[i] 为生成 i 对括号的所有合法字符串;
  • 递推:dp[i] = sum_{left=0…i-1} “(” + dp[left] + “)” + dp[i-1-left];
  • 思想与「96. 不同的二叉搜索树」的卡塔兰结构划分一致。
graph TDA[dp[0] = [""]] --> B[计算 dp[1..n]]B --> C{i from 1..n}C --> D[left from 0..i-1]D --> E[for s1 in dp[left], s2 in dp[i-1-left]]E --> F[dp[i] += "(" + s1 + ")" + s2]

数量验证(卡塔兰数)

  • C(n) = C(2n, n) / (n+1);
  • n: 0 1 2 3 4 5 6 7 8
  • C: 1 1 2 5 14 42 132 429 1430

📊 复杂度分析

算法时间复杂度空间复杂度说明
回溯(剪枝)O(Cn) 生成量级(Cn 为卡塔兰数)O(n)单条路径深度为 n
生成式 DP(拼接)O(Cn) 拼接生成O(Cn)存储所有子问题解集合
卡塔兰计数(仅计数)O(n)O(1)验证数量,不产出具体方案

🎯 示例(n=3)

输出(任意顺序均可):

((()))
(()())
(())()
()(())
()()()

回溯放置过程(路径示意):

( -> (( -> ((( -> ((() X-> (()( -> (()() -> (()()) ✓-> (() -> (()( -> (()() ✓
-> () -> ()( -> ()(( -> ()(() -> ()(()) ✓-> ()() -> ()()() ✓

💻 运行方式

cd 22
go run main.go

🧪 预期输出(节选)

=== 括号生成 算法测试 ===
n=1: 回溯=1, DP=1, Catalan=1
n=2: 回溯=2, DP=2, Catalan=2
n=3: 回溯=5, DP=5, Catalan=5
n=4: 回溯=14, DP=14, Catalan=14示例(n=3):
((()))
(()())
(())()
()(())
()()()

🔎 相关题目

    1. 有效的括号(判断合法性)
    1. 最长有效括号(字符串扫描)
    1. 不同的二叉搜索树(同属卡塔兰结构)
    1. 删除无效的括号(BFS/回溯)

回溯与卡塔兰结构相辅相成,构造与计数相互印证 ✅

完整题解代码

package mainimport ("fmt""sort"
)// 解法1:回溯(剪枝)
func generateParenthesisBacktrack(n int) []string {var ans []stringpath := make([]byte, 0, 2*n)var dfs func(l, r int)dfs = func(l, r int) {if l > n || r > l { // 剪枝return}if l == n && r == n {ans = append(ans, string(path))return}if l < n {path = append(path, '(')dfs(l+1, r)path = path[:len(path)-1]}if r < l {path = append(path, ')')dfs(l, r+1)path = path[:len(path)-1]}}dfs(0, 0)return ans
}// 解法2:生成式动态规划(卡塔兰结构拼接)
func generateParenthesisDP(n int) []string {dp := make([][]string, n+1)dp[0] = []string{""}for i := 1; i <= n; i++ {cur := make([]string, 0)for left := 0; left <= i-1; left++ {right := i - 1 - leftfor _, a := range dp[left] {for _, b := range dp[right] {cur = append(cur, "("+a+")"+b)}}}sort.Strings(cur) // 便于稳定输出dp[i] = cur}return dp[n]
}// 辅助:卡塔兰数计数(用于校验数量)
func catalan(n int) int {if n <= 1 {return 1}// C(n) = C(2n, n) / (n+1)num := 1den := 1for i := 1; i <= n; i++ {num *= (n + i) // 从 n+1 乘到 2nden *= i       // 从 1 乘到 n}return num / den / (n + 1)
}func main() {fmt.Println("=== 括号生成 算法测试 ===")for _, n := range []int{1, 2, 3, 4} {a := generateParenthesisBacktrack(n)b := generateParenthesisDP(n)fmt.Printf("n=%d: 回溯=%d, DP=%d, Catalan=%d\n", n, len(a), len(b), catalan(n))}fmt.Println("\n示例(n=3):")for _, s := range generateParenthesisBacktrack(3) {fmt.Println(s)}
}
http://www.dtcms.com/a/344809.html

相关文章:

  • 欲打造未来感十足的规划馆,应优先引入哪些沉浸式多媒体技术?
  • Spring Start Here 读书笔记:第9章 Using the Spring web scopes
  • 人脸识别驱动的工厂人体属性检测与预警机制
  • C#开源库ACadSharp读取dwg图元的示例
  • 为何她在“传递情报”时会被干扰?—— 探究 TCP 协议在无线环境中的信号干扰问题
  • 算法题复盘+代码解读(2)—— 两数之和
  • 【功能测试面试题】
  • 【数据结构】B+ 树——高度近似于菌丝网络——详细解说与其 C 代码实现
  • CVPR焦点 | 神经网络新范式:轻量化与精度并行,重塑视觉任务性能天花板
  • 解释一下,Linux,shell,Vmware,Ubuntu,以及Linux命令和shell命令的区别
  • 1337俚语的由来
  • Seaborn数据可视化实战:Seaborn时间序列可视化入门
  • Linux学习-网络编程2
  • .java->.class->java 虚拟机中运行
  • 51.Seata-TCC模式
  • 前端函数防抖
  • Nginx + Keepalived 实现高可用负载均衡集群
  • 前端桌面端解决方案技术选型:全面指南
  • 深入理解强化学习的target network
  • 3.5MM防水耳机插座
  • 为什么访问HTTPS站点时,会发生SSL证书错误
  • JAVA基础代码示例
  • SpringBoot -- 集成Spring Security (二)
  • LightGBM时序预测详解:从原理到 PSO 参数优化
  • 如何理解面向过程和面向对象,举例说明一下?
  • [docker/大数据]Spark快速入门
  • 【实时Linux实战系列】实时系统中的预测性维护策略
  • 能源行业合同管理难点有哪些?企业该如何应对?
  • FIFO核心原理与机制
  • QGIS 绿色版修正