递归代码的一般结构
int function(level,parm1,param2...){
//递归终结条件
if level>MAX_LEVEL;
process_result;
return;
//处理当前层逻辑
process(level,data..);
//下探到下一层
self.function(level+1,p1....);
//清理当前层
}
题目:
如何判断出这道题是一道递归题?
(n+1)个括号列表就是在n个括号的基础上添加一对括号即可,也就是1-2-3…-n-n+1是逐层迭代的,也可以理解为逐层递归。
解法1:暴力法
1.将所有可能的括号解列举出来,不管正确与否,例如(((((( 也算;
2.将不符合条件的解删除(创建一个评价函数)
如何判断是错误的解?
通过列举观察,我们可以发现一般像**())(()** (((() 这样的括号都是错误的,即解必须满足两个条件:
1.指针从左向右移动过程中,右括号’)‘的数量必须小于等于左括号’('的数量;
2.指针遍历完后,左右括号数量必须相等;
根据上诉条件,我们可以创建一个balance,遍历过程中,有一个左括号balabce++,否则–,如果遍历过程中balance<0,或者遍历完成后balance!=0,说明这个解是错误的。
代码如下:
class Solution {
void list_all(string str, int n, vector<string>& res) {
//首先写出脱离递归条件
if (str.size() == 2 * n) {
if (is_right(str) == 0)
res.push_back(str);
return;
}
list_all(str + '(', n, res);
list_all(str + ')', n, res);
}
int is_right(string &str) {
int balance = 0;
for (auto &i : str) {
if (i == '(')
balance++;
else
balance--;
if (balance < 0)
return balance;
}
return balance;
}
public:
vector<string> generateParenthesis(int n) {
vector<string>result;
list_all("", n, result);
return result;
}
};
list_all是递归函数,is_right是判断函数。
解法二:回溯法
我们其实可以在递归中就将这个判断条件加入进去,在函数中加入两个参数,left_num和right_num,分别代表左括号的数量和右括号的数量。在加括号的过程中,左括号可以随时加,但是不能大于n,右括号在小于左括号的情况下可以加。这样就可以使得所有的解满足条件。
代码如下:
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string>vec;
new_generator(vec,0,0,n,"");
return vec;
}
void new_generator(vector<string> &vec,int left_num,int right_num ,int sum,string s) {
if (left_num + right_num == 2 * sum) {
vec.push_back(s);
return;
}
if (left_num < sum)
new_generator(vec, left_num + 1, right_num, sum, s + "(");
if (right_num < left_num)
new_generator(vec, left_num, right_num + 1, sum, s + ")");
}
};
这个方法在leetcode上运行耗时0ms,算是最优方法。
解法三:动态规划
这个解法比较难以想到,它首先建立一个括号()
’ (’ a ‘)’ b
后续加的括号可以分成两部分a和b,a加到括号中,b加到括号外,通过循环可以依次求出f(1),f(2)…f(n)
具体可以见以下链接
https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/
python代码如下:
from typing import List
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
if n == 0:
return []
dp = [None for _ in range(n + 1)]
dp[0] = [""]
for i in range(1, n + 1):
cur = []
for j in range(i):
left = dp[j]
right = dp[i - j - 1]
for s1 in left:
for s2 in right:
cur.append("(" + s1 + ")" + s2)
dp[i] = cur
return dp[n]
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/
来源:力扣(LeetCode)
我用C++写了一个
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<vector<string>>vec(n+1);
vec[0].push_back("");
string str;
for (int i = 1; i <=n; i++) {
for(int j=0;j<i;j++){
for (string &str2:vec[j]) {
for (string &str1 : vec[i-1-j]) {
str = "(" + str1 + ")" + str2;
vec[i].push_back(str);
}
}
}
}
return vec[n];
}
};
这个方法的特点在于:
1、自底向上:从小规模问题开始,逐渐得到大规模问题的解集;
2、无后效性:后面的结果的得到,不会影响到前面的结果。