LeetCode Hot100【回溯-22. 括号生成】

题目:22. 括号生成

代码实现
class Solution {
public:
    vector<string> result;  // 存储所有有效的括号组合
    string path;            // 当前生成的括号组合

    // 回溯函数,n 为生成括号对数,left 和 right 分别为左括号和右括号的数量
    void backtracking(int n, int left, int right) {
        if (path.size() == n * 2) {  // 如果当前路径长度等于 2 * n,说明已经生成了一个有效组合
            result.push_back(path);  // 保存当前的组合
            return;
        }

        // 如果左括号的数量小于 n,继续添加左括号
        if (left < n) {
            path.push_back('(');
            backtracking(n, left + 1, right);  // 递归,增加左括号
            path.pop_back();  // 回溯,撤销选择
        }

        // 如果右括号的数量小于左括号,继续添加右括号
        if (right < left) {
            path.push_back(')');
            backtracking(n, left, right + 1);  // 递归,增加右括号
            path.pop_back();  // 回溯,撤销选择
        }
    }

    // 主函数,生成所有有效的括号组合
    vector<string> generateParenthesis(int n) {
        result.clear();
        path.clear();
        backtracking(n, 0, 0);  // 从左括号和右括号都为 0 开始
        return result;
    }
};

执行流程

示例输入
n = 3
回溯生成过程
  • n = 3,生成 3 对括号的所有有效组合。
生成过程(树形结构):
→ "(" → "(" → "(" (Left = 3, Right = 0) → ")" → "(()"
                    → ")" → "(()()"
                          → ")" → "(()())"
→ "(" → "(" → ")" (Left = 2, Right = 1) → ")" → "(())"
                          → ")" → "(())()"
最终输出
["((()))", "(()())", "(())()", "()(())", "()()()"]

关键思路

  1. 回溯法的框架
    • 当前字符串长度为 2 * n 时,说明生成了一个有效的组合,加入结果集。
    • 递归过程中,控制左括号和右括号的数量,确保始终有足够的右括号与左括号匹配。
  2. 合法的括号组合规则
    • 在生成括号时,左括号的数量不能超过 n,右括号的数量不能超过左括号的数量。
    • 使用两个变量 leftright 分别记录当前生成的左括号和右括号的数量。
  3. 回溯操作
    • 每次递归时通过 push_back() 添加括号,并在递归后通过 pop_back() 撤销选择。
  4. 终止条件
    • 如果当前字符串的长度已经是 2 * n,说明已经完成了一个有效组合,将其加入 result

时间 & 空间复杂度

操作时间复杂度空间复杂度
生成所有组合O(4n/√n)O(n)
  • 时间复杂度: 生成括号组合的问题可以通过卡特兰数来表示,时间复杂度为 O(4n/\sqrt{n}),其中 n是括号对数。
  • 空间复杂度: 由于使用了递归和保存路径,空间复杂度为 O(n)。

基础语法解析

1. path.push_back('(')path.push_back(')')

  • 选择左括号和右括号,每次递归时决定是否添加左括号或右括号。
path.push_back('(');
path.push_back(')');

2. backtracking(n, left + 1, right)backtracking(n, left, right + 1)

  • 递归调用,根据当前条件递归生成子问题。
    • left + 1:增加左括号数量;
    • right + 1:增加右括号数量。
backtracking(n, left + 1, right);  // 加入左括号
backtracking(n, left, right + 1);  // 加入右括号

3. path.pop_back()

  • 回溯操作,撤销最近一次的选择,即移除最后加入的括号。
path.pop_back();  // 回溯,撤销当前括号的选择

优化 & 变种

变种 1:给定字符集生成有效括号

如果给定的字符集是 {, }, (, ),可以通过相同的回溯思想生成有效的括号组合。只需要替换括号的符号即可。

void generateParenthesis(int n) {
    string path;
    generateBrackets(n, 0, 0, path);  // 替换括号符号进行回溯
}

总结

C++ 语法 / 结构作用
path.push_back('(')选择左括号,递归
path.push_back(')')选择右括号,递归
path.pop_back()回溯,撤销当前选择
时间复杂度: O(4^n / √n)生成所有组合的时间复杂度
空间复杂度: O(n)存储当前路径的空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值