【非常抱歉,第三层最下面两个节点画反了……】
题目:
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
"((()))", "(()())", "(())()", "()(())", "()()()"
解答:
回溯法(剪枝法)。不过虽然原理,写出来却是麻烦。还是要怪自己本科练习不够。先举一个 n=2 的例子:
一般的递归方法,总是要在从底层开始逐个向上层 return一个结果,否则所做的操作没有记录。但是回溯法如果只找到一个结果就 return,却是错误的。所以开始我的代码是这样的:
class Solution {
public:
set<string> tmp;
string gao(int left, int right, string it)
{
if(left == 0 && right == 0) { return it; }
string ret;
if(left == right) { tmp.insert(gao(left - 1, right, it + "(")); }
else {
if(left > 0) { tmp.insert(gao(left - 1, right, it + "(")); }
tmp.insert(gao(left, right - 1, it + ")"));
}
}
vector<string> generateParenthesis(int n) {
gao(n, n, string(""));
vector<string> ans(tmp.begin(), tmp.end());
return ans;
}
};
我还看了好久,很简单的一个错误:除了最底层向上 return 了一次。其他层都无法 return.
那怎么办?其他层总要 return 一点东西啊。但是,如果要return一个可行解的话,让我们看图,因为最底层(第4层)返回了一个结果,在第三层它的父亲处被存入一次,而且在第二层它的祖父处又被存入一次,其实是重复了……幸好set 是避免重复元素存在的。AC代码如下:
这里还用了一个小技巧,利用迭代器 set 转 vector 的构造函数:
vector<Type> test (_set.begin(), _set.end())
class Solution {
public:
set<string> tmp;
string gao(int left, int right, string it)
{
if(left == 0 && right == 0) { return it; }
string ret;
if(left == right) { ret = gao(left - 1, right, it + "("); tmp.insert(ret); }
else {
if(left > 0) { ret = gao(left - 1, right, it + "("); tmp.insert(ret); }
ret = gao(left, right - 1, it + ")"); tmp.insert(ret);
}
return ret;
}
vector<string> generateParenthesis(int n) {
gao(n, n, string(""));
vector<string> ans(tmp.begin(), tmp.end());
return ans;
}
};
现在想想自己当初真是够蠢……正确的回溯法应该这样的:
- 每次只递归一步,绝不多一步。这个和递归法是相同的道理;
- 只有最底层负责存入结果,存入一个脱离于函数的全局内存;
- 层与层之间,不再传递数据(因为回溯的答案不止一个,每层处理去重没必要,交给最底层存入)。但是每层必须有 return 返回上层,否则函数无法终止),return 一个空值
class Solution {
public:
vector<string> ans;
void gao(int left, int right, string it)
{
if(left == 0 && right == 0) { ans.push_back(it); return; }
if(left == right) { gao(left - 1, right, it + "("); }
else {
if(left > 0) { gao(left - 1, right, it + "("); }
gao(left, right - 1, it + ")");
}
return;<span style="white-space:pre"> </span>// important
}
vector<string> generateParenthesis(int n) {
gao(n, n, string(""));
return ans;
}
};