题目描述:
描述
有一个合法的字符串,合法是指左括号与右括号全部能配对,现在每次将这个序列第一个左括号删去,在将任意一个右括号删去,每次删去后的序列必须合法,求有多少种方法
输入
一个合法括号序列。
输出
方案数。
样例输入
()()()() (((())))()() |
样例输出
1 24 |
算法思想:
这道题惯性思维是使用深度搜索,深度搜索函数有两个参数,输入字符串与标志位,其中标志位用于标志查询的是左括号还是右括号,如果是左括号,则将去掉该左括号的字符串传入函数,并将标志设置为1,搜索右括号,如果匹配,则结果数加1,然后去掉该右括号,据需递归。
当然这道题目还可以使用逆向思维,因为从左往右扫描,每次选取的右括号会影响下次计算的结果值。所以可以考虑从右往左进行扫描,这样选取左括号就不会影响下次的扫描结果。从右往左扫描,如果是右括号则计数count + 1,如果遇到左括号,则表明该左括号可以有n中选择,且n–,继续扫描。
深度扫描源代码
#include<iostream>
#include<vector>
#include <string>
using namespace std;
int ans;
/*
判断是否匹配合法函数
*/
bool isr(string s)
{
int t = 0;
for (int i = 0; i<s.size(); i++)
{
if (s[i] == '(')
{
t++;
}
else
{
if (t<1)
{
return false;
}
else
{
t--;
}
}
}
return true;
}
/*
深度搜索函数
*/
int fun(string s, int k)
{
//当k = 0时,扫描查找左括号
if (k == 0)
{
if (s.size() == 0)
{
ans++;
return 0;
}
for (int i = 0; i<s.size(); i++)
{
//去除该左括号,扫描右括号
if (s[i] == '(')
{
string ss = s.substr(0, i);
cout << "ss = " << ss << endl;
string sb = s.substr(i + 1);
ss += sb;
cout << ss << " " << sb << endl;
fun(ss, 1);
break;
}
}
}
//扫描右括号
else
{
for (int i = 0; i<s.size(); i++)
{
if (s[i] == ')')
{
string ss = s.substr(0, i);
string sb = s.substr(i + 1);
ss += sb;
if (isr(ss))
{
fun(ss, 0);
}
}
}
}
return 0;
}
int main()
{
string s;
cin >> s;
ans = 0;
fun(s, 0);
cout << ans << endl;
return 0;
}
逆向扫描源代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include <string>
using namespace std;
const long long mod = 10000000007ll;
char ch[20000005];
long long ans = 1;
int tot;
int main()
{
string str;
cin >> str;
int len = str.size();
for (int i = len - 1; i >= 0; i--)
{
if (str[i] == ')')tot++;
else if (str[i] == '('){
ans = (ans*tot) % mod;
tot--;
}
}
printf("%I64d", ans);
return 0;
}
算法时间复杂度:
第一种深度递归方法时间复杂度是O(2^n),第二种逆向思维扫描的时间复杂度为O(n)。