news 2026/5/28 16:22:07

【力扣100题】72.括号生成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【力扣100题】72.括号生成

题目描述

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

示例 1:

输入:n = 3 输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1 输出:["()"]

提示:1 <= n <= 8


解题思路总览

方法时间复杂度空间复杂度说明
回溯O(4^n / sqrt(n))O(n)经典解法,指数级
动态规划O(n^2)O(n^2)卡特兰数递推
BFSO(4^n / sqrt(n))O(4^n)逐层构建

为什么用回溯?

  • 括号生成本质是「在每个位置选择左或右」
  • 必须保证有效性(右括号不能多于左括号)
  • 需要枚举所有可能的有效组合

完整代码

classSolution{public:vector<string>generateParenthesis(intn){vector<string>ans;stringpath(2*n,0);// 预分配长度为2n的字符串autotraversal=[&](thisauto&&traversal,intleft,intright)->void{if(right==n){ans.push_back(path);return;}// 可以放左括号if(left<n){path[left+right]='(';traversal(left+1,right);}// 可以放右括号(不能比左括号多)if(right<left){path[left+right]=')';traversal(left,right+1);}};traversal(0,0);returnans;}};

算法流程图

[开始] | [初始化 ans, path] | [递归 traversal(0, 0)] | [right == n?] | / 是 \ / 否 / \ 保存结果 [left < n?] 返回 | / 是 \ / 否 / \ [放左括号] [跳过左] path[pos]='(' | 递归 left+1 | [right < left?] | / 是 \ / 否 / \ [放右括号] [跳过右] path[pos]=')' 递归 right+1 | [返回]

决策树图解(n=2)

[根: left=0, right=0, pos=0] | +---------+---------+ | | 放 '(' (不放左,继续) left=1 | pos=1 | | right < left? | yes -> 放 ')' | right=1, pos=1 [left=1,right=0] | | [left=1,right=1] | | +-------+-------+ | | | | 放 '(' 放 ')' 放 ')' left=2 right<left right=2 == n pos=2 yes ans: "(())" | | [left=2,right=0] [left=1,right=1] | | 放 ')' 放 ')' right=1 right=2 == n pos=2 ans: "()()" | [left=2,right=1] | 放 ')' right=2 == n ans: "(())" 最终结果: ["(())", "()()"]

逐行解析

1. 预分配字符串

stringpath(2*n,0);
  • 长度为2*n的字符串,所有位置初始化为\0
  • 用位置索引left + right直接访问,O(1) 写入

2. C++23 新语法解析

autotraversal=[&](thisauto&&traversal,intleft,intright)->void{
  • this auto && traversal是 C++23 的显式 lambda 模板参数
  • this表示它是成员函数式的调用(可以递归)
  • 等价于普通写法:
function<void(int,int)>traversal=[&](intleft,intright){// ...};
  • 或者经典写法:
voidtraversal(intleft,intright){if(right==n){...}if(left<n){path[left+right]='(';traversal(left+1,right);}if(right<left){path[left+right]=')';traversal(left,right+1);}}

3. 终止条件

if(right==n){ans.push_back(path);return;}
  • right == n表示 n 个右括号都用完了
  • 此时left也必然等于 n(因为 right <= left)
  • 这就是一组有效的括号组合

4. 放左括号

if(left<n){path[left+right]='(';traversal(left+1,right);}
  • left < n表示还有左括号可用
  • 当前位置 =left + right(已放 left 个左,right 个右)
  • 放完后递归,left+1

5. 放右括号(关键合法性检查)

if(right<left){path[left+right]=')';traversal(left,right+1);}
  • right < left保证:右括号数量永远不会超过左括号
  • 这是括号有效性的核心保证
  • 如果没有这个检查,会产生)(这种非法情况

详细 trace 演示(n=2)

初始: path = "____", left=0, right=0 traversal(0, 0): right(0) < n(2)? 否,不终止 left(0) < n(2)? 是 path[0] = '(' traversal(1, 0) right(0) < left(0)? 否,不放右 traversal(1, 0): left<2: path[1]='(', traversal(2, 0) right<left? 0<1? 是, path[1]=')', traversal(1, 1) traversal(2, 0): left<2? 否 right<left? 0<2? 是, path[2]=')', traversal(2, 1) traversal(2, 1): left<2? 否 right<left? 1<2? 是, path[3]=')', traversal(2, 2) traversal(2, 2): right == n, ans.push_back("(())") traversal(1, 1): left<2? 是, path[2]='(', traversal(2, 1) right<left? 1<1? 否 traversal(2, 1): right<left? 1<2? 是, path[3]=')', traversal(2, 2) traversal(2, 2): right == n, ans.push_back("()()") 最终结果: ["(())", "()()"]

复杂度分析

时间复杂度:O(4^n / sqrt(n))

  • 卡特兰数,第 n 个括号组合数
  • 精确值 = C(2n, n) / (n + 1) ≈ 4^n / (n^(3/2) * sqrt(pi))
n组合数说明
11()
22(()), ()()
35((())), (()()), (())(), ()(()), ()()()
414
542
81430

空间复杂度:O(n)

  • 递归栈最大深度 = 2n
  • path 字符串长度 = 2n

常见错误

错误1:合法性检查写错

// 错误:写成 right <= left 会允许 right == leftif(right<=left){path[left+right]=')';traversal(left,right+1);}// 正确:右括号必须严格少于左括号才能放if(right<left){path[left+right]=')';traversal(left,right+1);}

错误2:终止条件写错

// 错误:写成 left == n 不够if(left==n){ans.push_back(path);return;}// 问题:如果 right < left,还没放完右括号就提前返回了// 正确:必须右括号用完才算完成if(right==n){ans.push_back(path);return;}

错误3:位置计算错误

// 错误:只用 right 当位置path[right]='(';traversal(left,right+1);// 正确:用 left + right 当位置path[left+right]='(';traversal(left+1,right);

面试追问 FAQ

问题回答
为什么 right < left 而不是 right <= left?右括号必须严格少于左括号才能放,否则会出现)(的非法情况。比如(()可以放右,但()(不能放右
能不用递归吗?可以用迭代,但递归最直观,n 最大才 8,递归深度可控
卡特兰数是什么?括号组合数是第 n 个卡特兰数 C(2n,n)/(n+1),这是典型的卡特兰数应用
如何按字典序输出?题目通常不要求,但可以先放左再放右得到字典序
如何判断括号有效性?本题本身就是验证,但可以用栈:左括号入栈,右括号出栈检查匹配

相关题目对比

题目难度核心区别
20. 有效的括号简单验证括号是否合法(栈)
32. 最长有效括号困难最长合法子串长度
241. 为运算表达式加括号中等给表达式加括号改变优先级
678. 有效的括号字符串中等判断是否有合法括号串(含 * 号)

举一反三

什么时候用回溯?

  1. 问题的解空间是树状结构
  2. 每个节点有多个分支选择
  3. 需要枚举所有可能的解

括号问题的通用模式:

放左括号的条件:left < n 放右括号的条件:right < left 终止条件:right == n

卡特兰数应用场景:

场景说明
括号生成本题
二叉树结构计数n 个节点的不同二叉树数
买卖股票问题含冷冻期的交易次数
出栈顺序问题n 个元素的不同出栈序列数

总结

要点说明
核心思想回溯 + 合法性检查
关键条件放右括号:right < left
终止条件right == n
位置计算left + right
时间复杂度O(4^n / sqrt(n)),卡特兰数
空间复杂度O(n)
C++23 语法this auto && traversal显式 lambda 模板参数

完整测试代码

#include<iostream>#include<vector>#include<string>usingnamespacestd;classSolution{public:vector<string>generateParenthesis(intn){vector<string>ans;stringpath(2*n,0);autotraversal=[&](thisauto&&traversal,intleft,intright)->void{if(right==n){ans.push_back(path);return;}if(left<n){path[left+right]='(';traversal(left+1,right);}if(right<left){path[left+right]=')';traversal(left,right+1);}};traversal(0,0);returnans;}};intmain(){Solution s;for(intn=1;n<=3;n++){cout<<"n = "<<n<<":"<<endl;vector<string>ans=s.generateParenthesis(n);cout<<"[";for(inti=0;i<ans.size();i++){cout<<"\""<<ans[i]<<"\"";if(i<ans.size()-1)cout<<", ";}cout<<"]"<<endl<<endl;}return0;}

运行结果:

n = 1: ["()"] n = 2: ["(())", "()()"] n = 3: ["((()))", "(()())", "(())()", "()(())", "()()()"]

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 16:15:18

Claude Skills深度解析:从提示词到情境设计的AI智能体构建指南

1. 项目概述&#xff1a;重新定义Claude中的“技能”如果你最近在深度使用Claude&#xff0c;尤其是Anthropic推出的Claude桌面应用或企业版&#xff0c;你很可能已经接触到了一个名为“Skills”&#xff08;技能&#xff09;的功能。乍一看&#xff0c;很多人会下意识地认为&a…

作者头像 李华
网站建设 2026/5/28 16:15:18

基于TMP36与Arduino的高精度温度监测系统:从电路设计到软件校准全解析

1. 项目概述与核心思路温度监测是嵌入式开发和物联网应用中最基础也最频繁的需求之一。无论是智能家居中的环境调控&#xff0c;还是工业场景下的设备状态监控&#xff0c;一个稳定、准确的温度数据采集系统都是基石。这次分享的项目&#xff0c;就是围绕经典的模拟温度传感器T…

作者头像 李华
网站建设 2026/5/28 16:15:02

从全国电设F题到实战:OpenMV数字识别核心技术与避坑指南

1. OpenMV数字识别入门指南 全国电子设计大赛F题中&#xff0c;OpenMV数字识别是许多参赛队伍遇到的第一个技术门槛。作为一个曾经在比赛中摸爬滚打的过来人&#xff0c;我想分享一些实战经验。OpenMV4虽然只有1MB内存&#xff0c;但通过合理优化&#xff0c;完全可以完成稳定的…

作者头像 李华
网站建设 2026/5/28 16:14:29

Taotoken用量看板如何帮助开发者分析与优化API调用模式

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 Taotoken用量看板如何帮助开发者分析与优化API调用模式 对于依赖大模型API进行开发的团队或个人而言&#xff0c;成本控制与效率优…

作者头像 李华