给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
(1)暴力法:(参考答案)
原理:
1,其实就是列出所有括号的组合,只能有6个半括号;
2,核心思想是双递归,双递归可以保证拿到所有可能的半括号组合,并且没有重复,具体原理我也不甚明白,但是推荐在IDE上面debug调试,一步一步多看几次结果,保证你可以明白这个工作原理;
3,拿到组合进行判断,把符合条件(闭合的)存到结果集合里面;
class Solution {
public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
generateAll(result,new char[2 * n],0);
return result;
}
//双递归列出所有可能的组合
public void generateAll(List<String> result, char[] current,int pos) {
if (pos == current.length) {
if (valid(current))
result.add(new String(current));
} else {
current[pos] = '(';
generateAll(result,current,pos + 1);
current[pos] = ')';
generateAll(result,current,pos + 1);
}
}
//判断这个组合是否符合条件
public boolean valid(char[] current) {
int balance = 0;
for (Character c : current) {
if (c == '(') balance ++;
else balance --;
if (balance < 0) return false;
}
return (balance == 0);
}
}
(2)回溯法
原理:
1,也是使用双递归,但是加上条件,只能是n个成对半括号组成,并且成闭合状态
2,我们只要符合条件的,也就是从open个左半括号开始递归,不断改变位置而已
3,还是建议debug调试,多看几次执行过程,包你有所收获。
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList();
backtrack(ans, "", 0, 0, n);
return ans;
}
//左右括号个只有三个,我们只在组合为有效序列再添加,只拿到有效组合
public void backtrack(List<String> ans, String cur, int open, int close, int max){
if (cur.length() == 2 * max) {
ans.add(cur);
return;
}
//先添加左括号
if (open < max)
backtrack (ans,cur + "(",open + 1,close,max);
//右括号保证和左括号数量一致
if (close < open)
backtrack (ans,cur + ")",open,close + 1,max);
}
}
(3)闭合数
原理:
1,和方法二类似,括号正确组合是闭合数,且括号成对闭合出现
2,还是双递归,只不过是放在for循环中了,相对比较难
3,还是多看几次debug执行过程慢慢理解吧
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList();
if (n == 0) {
ans.add("");
} else {
for (int c = 0; c < n; ++c)
for (String left: generateParenthesis(c))
for (String right: generateParenthesis(n-1-c))
ans.add("(" + left + ")" + right);
}
return ans;
}
}