【蓝桥杯】历届试题 正则问题(深度优先搜索dfs)

历届试题 正则问题

问题描述

考虑一种简单的正则表达式:
只由 x ( ) | 组成的正则表达式。
小明想求出这个正则表达式能接受的最长字符串的长度。
例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是 6。

输入格式

一个由 x()| 组成的正则表达式。输入长度不超过 100,保证合法。

输出格式

这个正则表达式能接受的最长字符串的长度。

样例输入

((xx|xxx)x|(x|xx))xx

样例输出

6



—— 柳暗花明——


对于题目给出的正则表达式,由于其存在着多重括号,那么对于某个式子而言其就必然需要用到回溯算法来对上一层括号中的内容进行反馈。换言之,本题用搜索算法来进行求解是相当合适的。

再看数据范围,输入字符串长度不超过100,这更一步确定了搜索算法的适用性。当然,是深度优先搜索。

接下来就以搜索算法的视角对本题进行分析。

首先要知道,当程序一遇到 ( 时,我们就需要进入一层 dfs,这一层 dfs 的任务是确定在当前这对括号中其所能接受字符串的最大长度。尽管在当前的这对括号中,也许还有多重括号,但是请忽略掉这些,因为我们只需要关心当前 dfs 的当前搜索任务,更深一层的自然有其对应的 dfs 以完成。而当我们一遇到 )(在当前 dfs 中),就说明已经将当前一对 () 中的结果遍历完毕,接下来直接返回遍历的结果即可。

注意到在一对 () 中是有可能遇到 | 运算的,这个的处理办法也很简单,我们事先定义两个变量 n u m num num a n s ans ans 分别存放当前遍历某个连续 * 串的长度和当前遍历连续 * 串的最大长度,每当一遇到 | 时,我们就比较当前的 n u m num num a n s ans ans,如果 n u m num num 更大就更新 a n s ans ans,否则 a n s ans ans 不变,最后令 n u m = 0 num=0 num=0

同样地,在某个 dfs 结束的时候(即遇到 ) 的时候),我们也需要判断 a n s ans ans 是否需要更新,规则同上。而统计连续 * 串的长度的任务也就是通过 n u m num num 完成的了,即一遇到 * 就令 n u m + + num++ num++

细心的同学可能已经发现,上面的分析实际上就是一系列的 if 条件,而其后的行为描述正是 if 语句中所需要执行的代码。如果仍然对上面的描述不是很清晰的同学,建议直接看代码,如下:



—— 又一村 ——


#include<iostream>
#include<string>
using namespace std;

string str;
int pos,len;

int dfs()
{
	int num=0,ans=0;
	while(pos<len)
	{
		if(str[pos]=='('){
			pos++;
			num+=dfs();
		}
		else if(str[pos]==')'){
			pos++;
			break;
		}
		else if(str[pos]=='|'){
			pos++;
			ans=max(num,ans);
			num=0;
		}
		else{
			num++;
			pos++;
		}
	}
	ans=max(num,ans);
	return ans;
}
 
int main()
{
	cin>>str;
	pos=0,len=str.length();
	cout<<dfs()<<endl;
	return 0;
}

END


评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

theSerein

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值