算法-回溯-生成括号组合
1 题目概述
1.1 题目出处
https://leetcode-cn.com/problems/generate-parentheses/
1.2 题目描述
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3
输出:[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
2 回溯法
2.1 思路
这段转自组合总和-解题思路
回溯法的解体框架是什么呢,解决一个回溯问题,实际上就是一个决策树的遍历过程。一般来说,我们需要解决三个问题:
- 路径:也就是已经做出的选择。
- 选择列表:也就是你当前可以做的选择。
- 结束条件:也就是到达决策树底层,无法再做选择的条件。
其中最关键的点就是:在递归之前做选择,在递归之后撤销选择。
LinkedList result = new LinkedList();
public void backtrack(路径,选择列表){
if(满足结束条件){
result.add(结果);
}
for(选择:选择列表){
做出选择;
backtrack(路径,选择列表);
撤销选择;
}
}
这里我们每次回溯递归时的选择列表就只有两个:选左括号或选右括号,而且还要注意添加左括号规则为必须先于右括号添加(也就是说不能先有右括号再添加左括号)、添加右括号规则为之前的右括号数量小于左括号。
这个也能算是个DFS深度优先遍历。
2.2 代码
class Solution {
List<String> resultList = new LinkedList<>();
public List<String> generateParenthesis(int n) {
if(n == 0){
return resultList;
}
// 添加左括号规则为必须先于右括号添加
// 添加右括号规则为之前的右括号数量小于左括号
backtrack(n, new StringBuilder(), 0, 0);
return resultList;
}
private void backtrack(int n, StringBuilder tmpSb, int left, int right){
StringBuilder newSb = new StringBuilder(tmpSb);
if(left == right && left == n){
// 结束条件
resultList.add(newSb.toString());
return;
}
if(left < n){
// 添加左括号
newSb.append("(");
backtrack(n, newSb, left + 1, right);
// newSb.deleteCharAt(newSb.length() - 1);
newSb.setLength(left + right);
}
if(right < left){
// 添加右括号
newSb.append(")");
backtrack(n, newSb, left, right + 1);
// newSb.deleteCharAt(newSb.length() - 1);
newSb.setLength(left + right);
}
// 其他情况被剪枝
}
}
2.3 时间复杂度
请参考Leetcode-括号生成官方关于该算法时间复杂度解释,有点复杂。
2.4 空间复杂度
O(n)
- 除了答案resultList,所需空间取决于递归栈的深度,每一层递归函数需要 O(1),最多递归 2n层,因此空间复杂度为 O(n)。