【蓝桥杯】试题 历届试题 正则问题

本文探讨了一种正则表达式匹配问题,通过递归函数设计,解决只由'x()'|组成的表达式能接受的最长字符串长度。通过分解为因子、序列和表达式,展示了如何运用自顶向下策略求解并给出样例代码实现。
资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

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

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。

输入格式

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

输出格式

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

样例输入

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

样例输出

6

可以定性为一个字符串的表达式问题,拥有不同优先级多种运算。通常使用递归方法可以简明地写出。我们可以根据严谨的逻辑写出 dfs 函数,通过递归栈来帮助实现运算顺序。在本题当中,需要改变运算顺序的是括号出现的地方,其他地方可以直接顺序计算。

本题可以直接用一个 dfs 函数定义 算式的计算 ,在读到括号时嵌套调用 dfs 计算括号里的算式。

事实上,递归可以发生在多个函数之间,只需实现做好函数的签名即可。这是一种自顶向下的设计思路,我们可以把这个表达式的计算进一步细化为三个部分:表达式、因子、序列。

  • 表达式 可以展开成 因子 | 因子 | ... 这样用 或运算 连接的多个因子,值是其中因子的最大值。
  • 因子 可以展开成 序列(表达式) 的任意排列,值是它们的和。
  • 序列 就是一连串的 x,值是 x 的计数。

详见如下代码:

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string s;
int i = 0;	// s[i]
int n;		// s.length()

int fact();
int seq();

// exp = fact | fact ...
int exp() {
	int res = fact();
	while (s[i] == '|') {
		++i;
		res = max(res, fact());
	}
	return res;
}

// fact = seq or (exp)seq ...
int fact() {
	int res = 0;
	while (i < n && (s[i] == '(' || s[i] == 'x')) {
		if (s[i] == '(') {
			++i;
			res += exp();
			++i;	// ')'
		} else if (s[i] == 'x') {
			res += seq();
		}
	}
	return res;
}

// xxx
int seq() {
	int res = 0;
	while (s[i] == 'x') {
		++i;
		++res;
	}
	return res;
}

int main() {
	cin >> s;
	n = s.size();
	cout << exp() << endl;
	return 0;
}

这样的思路有助于将复杂的问题拆解,每次只专心一个局部的实现,但是对于严谨性的要求也是一分不差的。尤其是对于更小规模问题的准确定义,不应当遗漏掉任何合法的情况。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值