题目大意:给定n对圆括号,写一个函数求出所有的匹配组合。
例如:n=3,则所有的匹配组合为:
"((()))", "(()())", "(())()", "()(())", "()()()"
这个排列组合在做一次算法的笔试题遇到过,要求n=6时的所有可能组合的数目。当时没做出来,这次又遇到,查了一下,发现这种形式的问题,都是满足卡塔兰数的。详细说明见百度百科。因此算法的求解和这个没多大关系。
思路:这种题目是求遍历各种可能,因此可用深度遍历。
1、初始,左括号和右括号个数都为n,可以考虑,确定一个左括号为结果string的第一个元素,然后求解左括号为n-1,右括号为n的遍历情况。
2、对于左括号为n-1,右括号为n的情况,此时string下一个元素有两种情况:
a、为左括号,加入左括号为string的第二个元素,此时即可转换为左括号为n-2,右括号为n的子问题。
b、为右括号,加入右括号为string的第二个元素,此时即可转换为左括号为n-1,右括号为n-1的子问题。
此时,需注意,剩余的子问题必须是右括号大于左括号。
3、直到遇到左括号和右括号数目都为0时,此刻就找到了一种可能,加入到结果vector<string> resu中。
这道题花了一上午加中午的时间来思考和求解,期间先是了解了卡特兰数的一些知识和应用,然后发现对于解题并没有什么帮助。只好继续自己思考如何用深度遍历来求解,改了多次,终于比较简洁的实现了此算法。
下面是ac的代码,非常简洁,运行时间0ms:
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> resu;
string ss;
match(n,n,ss,resu);
return resu;
}
void match(int left,int right,string &ss,vector<string>& resu)
{
if(left==0&&right==0)
{
resu.push_back(ss);
return;
}
if(left>0)
{
ss+='(';
match(left-1,right,ss,resu);
ss.erase(ss.end()-1);
}
if(right>0&&right>left)
{
ss+=')';
match(left,right-1,ss,resu);
ss.erase(ss.end()-1);
}
return;
}
};
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
addingpar(res, "", n, 0);
return res;
}
void addingpar(vector<string> &v, string str, int n, int m){
if(n==0 && m==0) {
v.push_back(str);
return;
}
if(m > 0){ addingpar(v, str+")", n, m-1); }
if(n > 0){ addingpar(v, str+"(", n-1, m+1); }
}
};