29、括号生成
题目
29.0、暴力解法
枚举出所有的可能,符合条件的写入结果集里面
public:
//暴力解法
vector<string> generateParenthesis0(int n)
{
vector<string> result;
string temp = "";
depth(result, 2 * n, temp);
return result;
}
private:
void depth(vector<string>& result, int n, string& temp)
{
if (n == temp.size())
{
if(judge2(temp))result.push_back(temp);
}
else
{
temp.push_back('(');
depth(result, n, temp);
temp.pop_back();
temp.push_back(')');
depth(result, n, temp);
temp.pop_back();
}
}
//贪心算法的求是否匹配
bool judge1(string& s)
{
stack<char> data;
for (auto& i : s)
{
if (!data.empty() && data.top() == '(' && i == ')')data.pop();
else data.push(i);
}
return data.empty();
}
//只遍历一遍的求是否匹配(仅限于对只有一种匹配符的情况,如果有多对匹配符,还是需要使用贪心算法)
bool judge2(string& s)
{
int flag = 0;
for (auto& i : s)
{
if (i == '(')flag++;
else flag--;
if (flag < 0)return false;
}
return flag == 0;
}
时间复杂度:O(2^2n * n)枚举了所有可能数量是2^2n,判断是否符合条件开销是n
空间复杂度:O(n)需要递归n层
29.1、回溯法
对于暴力枚举做一定的筛选,设‘(’的数量是x,‘)’的数量是y,需要生成n对
筛选,x < n,y < x
public:
//回溯法,暴力解法的优化版本
vector<string> generateParenthesis1(int n)
{
vector<string> result;
string temp = "";
depth2(result, 0, 0, n, temp);
return result;
}
private:
void depth2(vector<string>& result, int openIndex, int closeIndex, int n, string& temp)
{
if (2 * n == temp.size())
{
result.push_back(temp);
return;
}
if (openIndex < n)
{
temp.push_back('(');
depth2(result, openIndex + 1, closeIndex, n, temp);
temp.pop_back();
}
if (closeIndex < openIndex)
{
temp.push_back(')');
depth2(result, openIndex, closeIndex + 1, n, temp);
temp.pop_back();
}
}
时间复杂度:这里时间复杂度的计算超出了专业范畴,只需要知道比暴力快就行了
空间复杂度:O(n)需要递归n层
29.2、按括号序列的长度递归
和回溯法类似
每一个合法的括号序列都符合(a)b,其中a,b均为合法括号序列,也可以为空
枚举a的所有可能,b的所有可能,再拼接起来就是结果集,有点动态规划的意思
仔细看一下回溯法中的递归过程,其实原理是和这个一样的
这里不给代码了(俺也懒得写了。。。)
时间复杂度:和回溯法一样
空间复杂度:需要和时间复杂度一样大小的空间,来记录不同的状态
这个代码实现晦涩难懂,而且并不是最优解,了解即可。