1. 问题描述:
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。
示例:
输入:n = 3
输出:[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses
2. 思路分析:
① 之前解决这个括号生成的问题的时候使用的是dfs的方法,今天在领扣做题的时候发现了这道题目是每日一题,所以看了一下官方的题解看一下他们是怎么样解决的,其中第一种方法是暴力破解,整体的思路还是比较容易想到的,我自己也实现了一遍暴力破解的方法,第二种方法使用的是方法与我之前写的dfs的代码的思路是一样的,需要记录当前的左括号与右括号的数量发现当前合理的情况下才添加对应的括号往下进行递归,只是在官方的题解中处理的细节与我自己写的有所不同,第三种方法是比较难想到也比较难理解,因为使用的是java语言,所以我使用了idea的debug进行调试,在debug的时候使用简单一点的数字来进行递归这样的话整个的思路也是比较好理解的,比如生成数字2或者3的括号是最容易理解的,我感觉最难理解的是官方提供的方法三的解法,我们在理解好其余两种的解法的基础上,最好也是学习一下方法三的思路,对于我们在递归理解代码是非常有帮助的
② 下面是我对于官方提供的方法三的一些理解:
1)它主要是分为两部分进行递归,然后将两部分与左右括号拼接起来生成最后的长度为2 * n的括号序列,在for循环中尝试左边括号序列可能的情况与右边序列的情况
2)比如需要生成长度为3的括号序列,在循环中尝试左边的括号为0对,那么肯定是右边的两对进行递归,为什么是两对呢?因为在拼接的时候需要加上左括号与右括号,所以需要减少一对括号,0对括号的话返回"",两对括号又可以进行递归分为0对、一对括号与一对、0对括号进行递归,而1对括号返回的为"()",而两对括号的情况下返回的结果为"()()"与"(())",然后递归返回到最少一层,尝试左边括号为1对,右边括号为一对的情况,一对的情况又进行递归下去,最后尝试左边括号为2对,右边括号为1对的情况
1对括号递归返回"()"
两对括号返回:"()()" "(())"
0 ------> 2 : "(" + "" + " )" + "()()" "(" + "" + " )" + "(())" ====》"()()()" 与 "()(())"
1 -------> 1: "(" + "()" + " )" + "()" ======》"(())()"
2-------->0: "(" + "()()" + ")" "(" + "(()) + ")" =====》 "(()())" 与 "((()))"
使用debug调试会比较好理解
3. 代码如下:
自己写的暴力破解:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Solution {
/*纯暴力破解*/
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
recursion(n, 0, "");
return res;
}
private void recursion(int n, int pos, String cur) {
if (pos == 2 * n){
if (isvalid(cur)){
res.add(cur);
}
return;
}
/*两个平行状态*/
recursion(n, pos + 1, cur + "(");
recursion(n, pos + 1, cur + ")");
}
private boolean isvalid(String cur) {
/*计算左右括号的数量是否匹配: 只需要统计左右括号的数量是否相等*/
int count = 0;
for (int i = 0; i < cur.length(); ++i){
char c = cur.charAt(i);
if (c == '(') count++;
if (count > cur.length() / 2) return false;
else if (c == ')') count--;
if (count < 0) return false;
}
return count == 0;
}
}
官方的暴力破解:
class Solution {
public List<String> generateParenthesis(int n) {
List<String> combinations = new ArrayList();
generateAll(new char[2 * n], 0, combinations);
return combinations;
}
public void generateAll(char[] current, int pos, List<String> result) {
if (pos == current.length) {
if (valid(current))
result.add(new String(current));
} else {
current[pos] = '(';
generateAll(current, pos+1, result);
current[pos] = ')';
generateAll(current, pos+1, result);
}
}
public boolean valid(char[] current) {
int balance = 0;
for (char c: current) {
if (c == '(') balance++;
else balance--;
if (balance < 0) return false;
}
return (balance == 0);
}
}
方法三:
class Solution {
ArrayList[] cache = new ArrayList[100];
public List<String> generate(int n) {
if (cache[n] != null) {
return cache[n];
}
ArrayList<String> ans = new ArrayList();
if (n == 0) {
ans.add("");
} else {
for (int c = 0; c < n; ++c)
for (String left: generate(c))
for (String right: generate(n - 1 - c))
ans.add("(" + left + ")" + right);
}
cache[n] = ans;
return ans;
}
public List<String> generateParenthesis(int n) {
return generate(n);
}
}