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

LeetCodehot 力扣热图100 括号生成

class Solution {
public:
    vector<string> ans; // 存储所有有效括号组合的结果集
    
    vector<string> generateParenthesis(int n) {
        string s; // 当前构建的括号字符串
        backtrack(0, 0, n, s); // 初始调用回溯函数
        return ans;
    }
    
    void backtrack(int open, int close, int n, string &s) {
        // 终止条件:当前字符串长度等于2n,说明得到一个有效组合
        if (s.size() == 2 * n) {
            ans.push_back(s);
            return;
        }
        
        // 添加左括号的条件:已使用左括号数小于n
        if (open < n) {
            s.push_back('('); // 选择:添加左括号
            backtrack(open + 1, close, n, s); // 递归探索后续可能性
            s.pop_back(); // 回溯:撤销选择,尝试其他可能性
        }
        
        // 添加右括号的条件:已使用右括号数小于左括号数
        if (close < open) {
            s.push_back(')'); // 选择:添加右括号
            backtrack(open, close + 1, n, s); // 递归探索后续可能性
            s.pop_back(); // 回溯:撤销选择,尝试其他可能性
        }
    }
};

以下是当 `n=3` 时,回溯算法生成所有有效括号组合的详细运行步骤和回溯过程分析:

---

### **递归步骤详解(n=3)**
#### **初始状态**
- `open=0`, `close=0`, `s=""`

---

#### **步骤1:添加第一个左括号**
```plaintext
s = "("
open=1, close=0
递归调用 backtrack(1,0,3,"(")
```

---

#### **步骤2:添加第二个左括号**
```plaintext
s = "(("
open=2, close=0
递归调用 backtrack(2,0,3,"((")
```

---

#### **步骤3:添加第三个左括号**
```plaintext
s = "((("
open=3, close=0
递归调用 backtrack(3,0,3,"(((")
```

---

#### **步骤4:添加右括号(close < open)**
```plaintext
s = "((()"
open=3, close=1
递归调用 backtrack(3,1,3,"((()")
```

---

#### **步骤5:继续添加右括号**
```plaintext
s = "((())"
open=3, close=2
递归调用 backtrack(3,2,3,"((())")
```

---

#### **步骤6:完成第一个有效组合**
```plaintext
s = "((()))"
open=3, close=3
递归终止,保存结果 "((()))"
回溯到步骤5 → s = "((())"
```

---

#### **步骤7:回溯并探索其他路径**
```plaintext
回溯到步骤4 → s = "((()"
添加右括号:
s = "((())"
open=3, close=2 → 重复步骤5-6,但已处理
继续回溯到步骤3 → s = "((("
无法添加更多左括号(open=3),添加右括号:
s = "((()"
open=3, close=1 → 重复步骤4
```

---

#### **步骤8:回溯到步骤2 → s = "(("**
```plaintext
添加右括号(close < open):
s = "(()"
open=2, close=1
递归调用 backtrack(2,1,3,"(()")
```

---

#### **步骤9:添加左括号**
```plaintext
s = "(()("
open=3, close=1
递归调用 backtrack(3,1,3,"(()(")
添加右括号:
s = "(()()"
open=3, close=2
递归调用 backtrack(3,2,3,"(()()")
继续添加右括号:
s = "(()())"
保存结果 "(()())"
回溯到 s = "(()()" → 弹出右括号
```

---

#### **步骤10:回溯到 s = "(()("**
```plaintext
无法添加左括号(open=3),添加右括号:
s = "(()())" → 已保存
继续回溯到 s = "(()"
```

---

#### **步骤11:回溯到 s = "(()"**
```plaintext
添加右括号(close < open):
s = "(())"
open=2, close=2
递归调用 backtrack(2,2,3,"(())")
```

---

#### **步骤12:添加左括号**
```plaintext
s = "(())("
open=3, close=2
递归调用 backtrack(3,2,3,"(())(")
添加右括号:
s = "(())()"
保存结果 "(())()"
回溯到 s = "(())(" → 弹出左括号
```

---

#### **步骤13:回溯到 s = "(())"**
```plaintext
添加右括号:
s = "(())" → 无法继续(close=2 < open=2 不成立)
回溯到 s = "(()"
```

---

#### **步骤14:回溯到步骤1 → s = "("**
```plaintext
添加右括号(close < open):
s = "()"
open=1, close=1
递归调用 backtrack(1,1,3,"()")
```

---

#### **步骤15:添加左括号**
```plaintext
s = "()("
open=2, close=1
递归调用 backtrack(2,1,3,"()(")
添加左括号:
s = "()(("
open=3, close=1
递归调用 backtrack(3,1,3,"()((")
添加右括号:
s = "()(()"
→ 继续递归直到生成 "()(())"
保存结果 "()(())"
回溯到 s = "()(()" → 弹出右括号
```

---

#### **步骤16:回溯到 s = "()(("**
```plaintext
添加右括号:
s = "()(()" → 重复
继续回溯到 s = "()("
添加右括号:
s = "()()"
open=2, close=2
递归调用 backtrack(2,2,3,"()()")
```

---

#### **步骤17:添加左括号**
```plaintext
s = "()()("
open=3, close=2
递归调用 backtrack(3,2,3,"()()(")
添加右括号:
s = "()()()"
保存结果 "()()()"
```

---

### **最终结果**
所有有效组合(共5种):
1. `((()))`
2. `(()())`
3. `(())()`
4. `()(())`
5. `()()()`

---

### **关键回溯路径图(简化版)**
```plaintext
开始(空字符串)
|
├─ 添加'(' → "("
│   ├─ 添加'(' → "(("
│   │   ├─ 添加'(' → "((("
│   │   │   └─ 添加')' → "((()" → ... → "((()))"
│   │   └─ 添加')' → "(()" → ... → "(()())", "(())()"
│   └─ 添加')' → "()"
│       ├─ 添加'(' → "()(" → ... → "()(())", "()()()"
│       └─ 添加')' → 无效(剪枝)
└─ 添加')' → 无效(剪枝)
```

---

### **算法核心逻辑**
1. **左括号优先**:只要左括号未达 `n`,优先添加左括号。
2. **右括号限制**:右括号数量必须小于左括号时才能添加。
3. **回溯剪枝**:通过 `s.pop_back()` 撤销无效尝试,避免重复路径。

此过程通过递归和回溯系统地探索所有可能的组合,并利用剪枝条件确保每一步都是有效的。


http://www.kler.cn/a/566969.html

相关文章:

  • 详解Pytorch:张量自动微分
  • word中把latex公式快速转换为word公式
  • 【Mark】记录用宝塔+Nginx+worldpress+域名遇到的跨域,301,127.0.0.1,CSS加载失败问题
  • ML.NET库学习019:使用 ML.NET 创建 GitHub 问题标签分类器
  • 奔图Pantum M7165DN黑白激光打印一体机报数据清除中…维修
  • 农作物叶子病害检测数据集VOC+YOLO格式5169张29类别
  • HTTP协议和HTTPS协议
  • 山石-Ultrasonic-好久不见45
  • 【计算机网络】常见tcp/udp对应的应用层协议,端口
  • 2025年4月1日-2日AutoCable 中国汽车线束线缆及连接技术创新峰会即将开幕
  • Apache DolphinScheduler系列3-任务配置经验分享
  • 模型优化之强化学习(RL)与监督微调(SFT)的区别和联系
  • 【多模态】Magma多模态AI Agent
  • 黑马Java面试教程_P5_微服务
  • 用大白话解释缓存Redis +MongoDB是什么有什么用怎么用
  • [Lc双指针_2] 盛水最多的容器 | 有效三角形的个数 | 和为S的两个数字
  • Spring Boot 消息队列(以RabbitMQ为例)
  • Java注释/JDK开发工具生成API/关键字、标识符规范
  • 企业级本地知识库部署指南(Windows优化版)
  • 什么是 Prompt?——一篇详细的介绍