1. 回溯算法核心思想与应用场景
回溯算法是一种通过探索所有可能的候选解来找出所有解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化来丢弃该解,即"回溯"并尝试其他可能性。
回溯法通常用于解决以下几类问题:
- 组合问题:从N个数中按规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后、解数独等
回溯法的本质是递归的暴力搜索,通过剪枝来提高效率。理解回溯算法需要掌握三个关键点:
- 递归函数的参数设计
- 递归终止条件
- 单层搜索的逻辑
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 括号生成问题详解
2.1 问题描述与解法分析
括号生成问题要求我们生成所有可能的并且有效的n对括号的组合。例如,当n=3时,有效的组合为:
code复制[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
这个问题可以通过回溯算法高效解决。关键在于理解有效括号的两个约束条件:
- 在任何位置,已放置的左括号数量不能超过n
- 在任何位置,已放置的右括号数量不能超过左括号数量
2.2 回溯实现细节
2.2.1 递归函数设计
cpp复制vector<string> result;
string current;
void backtrack(int left, int right, int n)
参数说明:
left:当前已使用的左括号数量right:当前已使用的右括号数量n:需要生成的括号对数
2.2.2 终止条件
当左右括号都使用了n个时,说明找到了一个有效组合:
cpp复制if (left == n && right == n) {
result.push_back(current);
return;
}
2.2.3 单层搜索逻辑
在每一层递归中,我们有两个选择:
- 添加左括号:前提是左括号数量小于n
- 添加右括号:前提是右括号数量小于左括号数量
cpp复制if (left < n) {
current.push_back('(');
backtrack(left + 1, right, n);
current.pop_back(); // 回溯
}
if (right < left) {
current.push_back(')');
backtrack(left, right + 1, n);
current.pop_back(); // 回溯
}
注意:这里的
right < left条件确保了任何时候右括号数量不超过左括号,这是生成有效括号的关键。
2.3 完整实现代码
cpp复制class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> result;
string current;
backtrack(result, current, 0, 0, n);
return result;
}
void backtrack(vector<string>& result, string& current, int left, int rig
