括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。
说明:解集不能包含重复的子集。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
分析:
方法:DFS+回溯
当 n = 1 时,可能情况就有 "((","()",")(","))",一共 4 种,满足条件的只有 "()"
当 n = 2 时,可能情况就有 "((((","((()","(())","(()(","()((","()()","())(","()))",")(((",")(()",")()(",")())","))((","))()",")))(","))))",一共 16 种,满足条件的只有 "(())","()()"
当 n = 3 时,可能的情况就有 64 种,不列举了,满足条件的只有 "((()))","(()())","(())()","()(())","()()()" 。
不难看出,n 的可能情况就有 2 的 2n 次方种,很容易让人想到二叉树,拿 n = 2 举例,可以画出解空间树:(有点丑,别介意)
创建高度为 2n 的二叉树,遍历节点,当左括号数小于右括号时不遍历下一个节点,每一个能走完的链表就是一个答案。
时间复杂度:O(2^2n) 实际运行要远远小于这个复杂度,一大半的节点是不遍历的
空间复杂度:O(2^2n)
class Solution {
//结果集
List<String> res = new ArrayList<>();
//存储单个结果
StringBuilder sb = new StringBuilder();
public List<String> generateParenthesis(int n) {
dfs(0, 0,n);
return res;
}
//i为前括号个数,j为后括号个数
//n为总括号数的一半
public void dfs(int i, int j, int n){
//后括号比前括号多或者前括号大于总长度一半,不符合条件
if(i < j || i > n){
return;
}
//j等于n停止遍历,记录结果
if(j == n){
res.add(sb.toString());
return;
}
//添加前括号
sb.append('(');
//深度遍历
dfs(i+1, j, n);
//恢复
sb.delete(sb.length()-1, sb.length());
//添加后括号
sb.append(')');
//深度遍历
dfs(i, j+1, n);
//恢复
sb.delete(sb.length()-1, sb.length());
}
}
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bracket-lcci