题目
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
思路
1.递归,控制左括号和右括号个数。
2.注意区分错误解法,与其他递归回溯leetcode17. 电话号码的字母组合不同的地方在于其他地方每次更改暂存值之后都会回溯至上一次位置,但此处容易被忽略导致值无法回溯。这里的关键参数都是简单类型,所以可以直接更改实参的值而不用中间变量回溯。
3.递归回溯的正确解法见解法4
实现
解法1
class Solution {
public:
vector<string> generateParenthesis(int n) {
if (n == 0) return {};
string tmp;
vector<string> res;
tmp.push_back('(');
func(1, 0, n, tmp, & res);
return res;
}
void func(int left, int right, int n, string tmp, vector<string>* res) {
if (left == n) {
if (right == n) {
res->push_back(tmp);
}
if (right < n) {
func(left, right + 1, n , tmp + ")", res);
}
} else if (left < n) {
if ( left == right) {
func(left + 1, right, n , tmp + "(", res);
}
if (left > right) {
func(left + 1, right, n , tmp + "(", res);
func(left, right + 1, n , tmp + ")", res);
}
}
}
};
解法2
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
add(n, n, res, "");
return res;
}
void add(int left, int right, vector<string>& res, string path) {
if (left == 0 && right == 0) {
res.push_back(path);
return;
}
if (left > 0) {
add(left - 1, right, res, path + "(");
}
if (right > 0 && right > left) {
add(left, right - 1, res, path + ")");
}
}
};
解法3错误
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
add(n, n, res, "");
return res;
}
void add(int left, int right, vector<string>& res, string path) {
if (left == 0 && right == 0) {
res.push_back(path);
}
if (left > 0) {
path += "(";
add(left - 1, right, res, path);
}
if (right > 0 && right > left) {
// 错误的原因是此处path的值已经被更改多次,而不是一次
path += ")";
add(left, right - 1, res, path);
}
}
};
解法4
错误解法修正:
若想使用中间变量回溯到上一次位置且值不被修改,需要在每次更改值后恢复原样
class Solution {
public:
vector<string> generateParenthesis(int n) {
if (n == 0) return {};
string tmp;
vector<string> res;
tmp.push_back('(');
func(1, 0, n, &tmp, & res);
return res;
}
void func(int left, int right, int n, string* tmp, vector<string>* res) {
if (left == n) {
if (right == n) {
res->push_back(*tmp);
}
if (right < n) {
tmp->push_back(')');
func(left, right + 1, n , tmp, res);
tmp->pop_back();
}
} else if (left < n) {
if ( left == right) {
tmp->push_back('(');
func(left + 1, right, n , tmp, res);
tmp->pop_back();
}
if (left > right) {
tmp->push_back('(');
func(left + 1, right, n , tmp, res);
tmp->pop_back();
tmp->push_back(')');
func(left, right + 1, n , tmp, res);
tmp->pop_back();
}
}
}
};