给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
当初的想法:
生成n个括号的排列组合,可以在生成n-1个括号的基础上进行处理,将括号分别加在其上一步实现的左面,右面,两边。
但是这会漏掉一些情况:当n=4时,“(())(())”这种情况会漏掉。
改进当初的想法:
生成n个括号的组合,依然是基于前面的结果进行处理,当初的想法只用到了第n-1步的值,导致结果会漏掉一些情况。这次不仅仅用到第n-1步的值,还会用到其他的结果,那就需要在求解的过程中将所有的结果保存。
其实本质思想是:动态规划
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<vector<string>> cell;
vector<string> c;
if(n<=0)
return c;
//为了便于处理,真正的存储结果从cell的第一行开始
cell.push_back(c);//第0行保存空值
c.push_back("()");
cell.push_back(c);//第一行是n=1时的结果
for(int i=2;i<=n;++i){
string temp="";
c.clear();
int p,q;
for(p=0;p<i;++p){
if(p==0){
q=i-1;
for(int k=0;k<cell[q].size();++k){//针对等于q时的每一个字符串进行处理
temp="()"+cell[q][k];
c.push_back(temp);//将当前情况下的结果保存
}
}
else{
for(int j=0;j<cell[p].size();++j){//针对等于p时的每一个字符串进行处理
temp='('+cell[p][j]+')';
if(p==i-1){//不再连接q;
c.push_back(temp);
continue;
}
q=i-1-p;
for(int k=0;k<cell[q].size();++k){//针对等于q时的每一个字符串进行处理
c.push_back(temp+cell[q][k]);//将当前情况下的结果保存
}
}
}
}
cell.push_back(c);
}
return cell[n];
}
};
比较精炼的写法
这里cell在n=0时,存入的是一个空串,大大方便了处理过程
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<vector<string>> cell;
vector<string> c;
if(n<=0)
return c;
//为了便于处理,真正的存储结果从cell的第一行开始
// c.push_back("");
// cell.push_back(c);//第0行保存空值
// c.clear();//一定要将c中的内容清除后,再来存放新的值
// c.push_back("()");
// cell.push_back(c);//第一行是n=1时的结果
/等价写法
cell.push_back({""});//第0行
cell.push_back({"()"});//第一行
for(int i=2;i<=n;++i){
string temp="";
c.clear();
int p,q;
for(p=0;p<i;++p){
cout<<"p="<<p<<" "<<cell[p].size()<<endl;
for(int j=0;j<cell[p].size();++j){//针对等于p时的每一个字符串进行处理
temp='('+cell[p][j]+')';
q=i-1-p;
cout<<"q="<<q<<" "<<cell[q].size()<<endl;
for(int k=0;k<cell[q].size();++k){//针对等于q时的每一个字符串进行处理
string str=temp+cell[q][k];
c.push_back(str);//将当前情况下的结果保存
}
}
}
cell.push_back(c);
}
return cell[n];
}
};
特别注意:下面这种写法就不适合先存到一个vector的变量c中,再将c push_back到cell中,因为cell预先分配了空间。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> c;
if(n<=0)
return c;
vector<vector<string>> cell(n+1);
cell[0]={""};
cell[1]={"()"};
for(int i=2;i<=n;++i){
c.clear();
for(int p=0;p<i;++p){
for(string t1:cell[p]){//针对等于p时的每一个字符串进行处理
int q=i-1-p;
for(string t2:cell[q]){//针对等于q时的每一个字符串进行处理
cell[i].push_back("("+t1+")"+t2);//将当前情况下的结果保存
}
}
}
}
return cell[n];
}
};
基本思想:回溯思想
参考:回溯
构建深度优先树:
class Solution {
public:
vector<string> generateParenthesis(int n) {
//采用回溯的思想
int left=n,right=n;
vector<string> res;
if(n<=0)
return res;
string c="";
fun(left,right,res,c);
return res;
}
private:
void fun(int left,int right,vector<string> &res,string &c){
if(left==0&&right==0){//左右括号数剩余为0时,保存结果
res.push_back(c);
//cout<
return;
}
else if(right<left){//剩余的右分支数<左分支数,剪枝
return;
}
if(left>0){//剩余左括号数>0,生成左分支
c+='(';
fun(left-1,right,res,c);
c.pop_back();//重置为原来的状态
}
if(right>0&&right>=left){//剩余右括号数>0,且剩余右括号数>左括号数,生成右分支
c+=')';
fun(left,right-1,res,c);
c.pop_back();//重置为原来的状态
}
}
};
说明:
二刷
回溯
class Solution {
public:
vector<string> generateParenthesis(int n) {
if(n < 1)
return vector<string>();
vector<string> res;
unordered_set<string> temp;
dfs(temp, "", 0, 0, n);
for(auto t : temp)
res.push_back(t);
return res;
}
private:
void dfs(unordered_set<string>& res, string temp, int l, int r, int n){
if(r > l || r > n || l > n)
return;
if(r + l == 2 * n){
res.insert(temp);
return;
}
dfs(res, temp + '(', l + 1, r, n);
dfs(res, temp + ')', l, r + 1, n);
}
};
回溯代码模板:
void (变量,&结果变量){
递归结束条件
当前情况下可能的选择
}
BFS:
广度优先遍历
struct Node{
string str;
int l;
int r;
Node(string s, int i, int j): str(s), l(i), r(j){}
};
class Solution {
public:
vector<string> generateParenthesis(int n) {
//bfs
vector<string> res;
queue<Node> q;
Node t("", 0 ,0);
q.push(t);
while(!q.empty()){
auto t = q.front();
q.pop();
if(t.l + t.r == 2 * n){
res.push_back(t.str);
continue;
}
if(t.l + 1 <= n){
q.push(Node(t.str + '(', t.l + 1, t.r));
}
if(t.r + 1 <= n && t.r + 1 <= t.l){
q.push(Node(t.str + ')', t.l, t.r + 1));
}
}
return res;
}
};
动态规划:
class Solution {
public:
vector<string> generateParenthesis(int n) {
//动态规划:基于之前的结果处理
vector<vector<string>> res(n + 1);
res[0] = {""};
res[1] = {"()"};
for(int i = 2; i <= n; ++i){
for(int p = 0; p < i; ++p){
for(auto s : res[p]){
int q = i - p - 1;
for(auto t : res[q]){
res[i].push_back("(" + s + ")" + t);
}
}
}
}
return res[n];
}
};