leetcode 22 括号生成
这是一道典型的回溯算法的题目,当然我看到dp也可以做,但是我认为回溯会直观一些,一般来讲有递归就有回溯,有回溯就有类似于pop_back的操作,但是这里看到了一种很巧妙的回溯方式,记录一下。
题目是给定一个n,求n个左括号和n个右括号一共可以弄出来怎样的合法括号组合,结果用vector
eg:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
首先定义回溯函数包括返回值和参数
因为我们需要的是某些中间的结果,比如已经凑好了组合,不需要返回值,因此返回值是void,另外我们需要统计左括号和右括号的个数,因此需要一个left 和一个 right
最后我们还需要一个path记录我们已经枚举到的字符串是什么样子的,因为遇到最终合理的字符串我们需要存下来,这个临时的枚举string叫做path
因此定义为 void back_tracing(string path, int left, int right)
什么时候结束呢?
当左右括号的数目都是n的时候结束,另外我们还需要一个剪枝,也就是当右括号的数目大于左括号的数目的时候,一定是不合法的,这里我觉得也不能叫做剪枝,应该算作是递归的一个终点,比如说:
()(())) 这种右括号比左括号多了一个,显然不管你在后面怎么增加,都是不合法的,即使你后面再添加一个左括号使得左右括号数量满足 == n,()(()))( 这都是不合法的,接下来,什么时候我们可以继续添加左括号呢? 当左括号数量还没到n的时候,同理右括号是一样的,前面我们已经处理了不合法的情况,这里添加左/右括号就不担心不合法了,感觉这里也挺难想的。添加完括号之后我们需要回溯,也就是把这个括号删掉,但是其实我们可以不删括号,反正下一步递归的时候我们要的是当前string + "("的结果,之后回溯的时候又要删掉,那我们不如不删,传参是时候传进去path + "(" 就好了。
下面可以对照代码看看。
class Solution {
public:
int sum;
vector<string> ans;
void back_tracing(string path, int left, int right) {
if(left < right) return;
if(left == sum && left == sum) {
ans.push_back(path);
return;
}
if(left < sum) {
back_tracing(path + "(", left + 1, right);
//path其实是没有修改的,因此这里隐含了一个回溯,也就是path -= "("
}
if(right < sum) {
back_tracing(path + ")", left, right + 1);
// 这里的回溯同理
}
}
vector<string> generateParenthesis(int n) {
if(n == 0) return ans;
sum = n;
//string tmp = ""; //省一点空间
back_tracing("", 0, 0);
return ans;
}
};

浙公网安备 33010602011771号