题目链接
一、题目描述
考虑一种简单的正则表达式:
只由 x ( ) | 组成的正则表达式。
小明想求出这个正则表达式能接受的最长字符串的长度。
例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。
输入格式
一个由x()|组成的正则表达式。
输出格式
输出所给正则表达式能接受的最长字符串的长度。
数据范围
输入长度不超过100,保证合法。
输入样例:
((xx|xxx)x|(x|xx))xx
输出样例:
6
解题思路
题目很明显是dfs问题,不过比较有意思的是,该题和其他一般的深搜问题有点不一样,本题的树根节点有两种,我们都知道画出一个递归树对写dfs代码有很大帮助。对于样例来说,我们可以画出,这样一颗树
在本题根节点是遇到括号 和 | ,画出图来就很简单啦。 dfs写多了就知道深搜最重要处理的是返回值的位置,还有传参操作,至于其他的逻辑判断操作和我们正常代码无异。而搜索树中,通常再返回值就在树根处,这很容易理解吧,因为我们需要向下搜索,靠不断回溯来处理问题,那么放回值就应该是在搜索完后的节点处,就是我们的树根。新手最常犯的就是在写递归问题时用脑子一直去想递归,但是其实我们只需要处理几个关键点,剩下的再去debug一下就能解决。
代码
针对本题我写了两种写法,第一种就是全局变量的方法来处理,好处是节省了一个数组空间标记,但可能有点难理解?
#include<bits/stdc++.h>
using namespace std;
string s;
int t = 0;
int dfs()
{
int res = 0;
while(t < s.size())
{
if(s[t] == '(')
{
t ++;
res += dfs();
// t ++;
}
else if(s[t] == '|')
{
t ++;
res = max(res,dfs());
return res;
}
else if(s[t] == ')')
{
t ++;
return res;
}
else
{
t ++ ;
res ++ ;
}
}
return res;
}
int main()
{
cin >> s;
cout<<dfs()<<endl;
return 0;
}
下面这种就是常用的传参法了,需要加一个st数组来判断状态
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
bool st[N];
string s;
int dfs(int t)
{
int res = 0;
for (int i = t; i < s.size(); i ++ )
{
if(!st[i]) //传参法深搜,需要进行标记,避免在循环中进行重复递归
{
st[i] = 1;
if(s[i] == '(')
{
res += dfs(i + 1);
}
else if(s[i] == '|')
{
res = max(dfs(i + 1),res);
return res; //此处返回很关键 这样才能避免res数据被覆盖 (返回值设在树的根节点,仔细观察树的结构)
}
else if(s[i] == ')')
{
return res;
}
else{
res ++ ;
}
}
}
return res;
}
int main()
{
cin >> s;
cout<<dfs(0)<<endl;
return 0;
}
总结
本题算是比较有代表性的搜索问题,再写dfs时,最好就是先画递归树,这样处理代码就能方便很多,也能解决掉返回值位置这个头大难的问题。