回溯+剪枝
本题的核心解题步骤如下:
- 递归函数传参:中间结果变量用于存放中间结果,左/右括号已经使用的次数
- 终止条件:左右括号都已经使用完
- 剪枝策略:当已经使用的左括号的数量,已经比已经使用的右括号的数量少时,说明中间结果变量中的左括号数量少于右括号,那么必然不可能合法,因此剪枝。
- 分别向中间变量中加入左括号和右括号,传入下一层递归中,代表继续遍历加入左括号或右括号后,所有的排列组合的可能性
class Solution {
public:
vector<string> ans;
void dfs(string cur, int left, int right, int n) {
// 终止条件:当左右括号都用完的时候,可以将中间结果加入最终结果集中
if (left == n && right == n) {
ans.push_back(cur);
}
// 剪枝:当已经使用的左括号的数量,已经比已经使用的右括号的数量少时
if (left < right) return;
// 当还剩余左括号时,将左括号加入中间变量中,代表向左子树递归
if (left < n) {
dfs(cur + "(", left + 1, right, n);
}
// 当还剩余右括号时,将右括号加入中间变量中,代表向右子树递归
if (right < n) {
dfs(cur + ")", left, right + 1, n);
}
}
vector<string> generateParenthesis(int n) {
if (n == 0) return ans;
dfs("", 0, 0, n);
return ans;
}
};
时间复杂度:O(2^n)
空间复杂度:O(1)