Leetcode 10 正则表达式 模拟穷举方法求解

首先吐槽下,太恶心 了......一开始以为很简单,后来发现细节太多了......一直修修改改限制条件花了6个小时

先敲下黑板:直接暴力模拟的匹配模式

思路: 首先对于两个序列都要加上游标 sp , pp  从起点0开始

如果二者相等不断下行,sp++,pp++ 【直至不相等或者越界时出来 】

未越界只是不等的时候,首先要区分下面3种不等的情形

         (1) s中字母与【'  '】不等,直接sp++,pp++

         (2) s中字母与【' '】不等 。(此时要考虑一下3种情况)

                        a.  是否是利用  *  来达到删除效果  ,如【 a  ,  c* a】故删除 【c* 】利用递归判断【a , a】

                        b.  是否是只复制1次,如【abc, a*b*c*】,故也要递归本身来判断

                        c.  是否是复制N次,直至不相等处,且每复制比对一次都需要调用自身的递归函数来判断

          (3) s中的字母与p中的字母不相等,此时要查看下p字母后面是否是*,是*可以删除当前字母还有救

                          如: ab,ac*b   (不等时候,sp指向b,pp指向c)

                          只需要将  pp+2 (pp指向b) 继续判断就行了

    越界时候,有以下3种情况

                (1)sp和pp同时越界,说明匹配至最后,说明字符串是匹配的

                (2)pp越界 sp没越界,一定不匹配

                (3)sp越界,但是pp没越界。此时比较复杂,需要考虑一下2种情况

                                   a. pp当前位置的字符是 * ,要判断  pp+1 至结尾能否抵消如 *a*b*c*d* 要判断a*b*c*d*这种

                                                          若能抵消则说明匹配

                                                          若不能抵消能否通过消除一个后进行匹配,如 abc,c*abc ,消除c*

                                                           消除能匹配就能匹配,消除不能匹配则s,p不能匹配     

                                   b. pp当前位置的字符不是*,是字母,则要判断pp至结尾的字符串能否抵消 如a*b*c*d* 这种

                                                          若能抵消则说明匹配

                                                          若不能抵消能否通过消除一个后进行匹配,如 abc,c*abc ,消除c*

                                                           消除能匹配就能匹配,消除不能匹配则s,p不能匹配     

 

 

#include<iostream>
#include<vector>
#include<string>
using  namespace std;
/*
*
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
".*" 表示可匹配零个或多个('*')任意字符('.')。
*/
bool clearOne(string p) {//空串返回false
	int p_len = p.length();
	int pp = 0;
	if (p.empty() || p == "")return false;
	if (((pp + 1) < p.length()) && (p.at(pp + 1) == '*')) return true;
	return false;
}
bool check_pnull(string p) {//判断规则p剩余部分是否可以抵消
	int p_len = p.length();
	int pp = 0;
	if (p.empty() || p == "")return true;

	while (pp < p_len) {//字母在
		if (pp + 1 < p_len) {//*号在
			if (p.at(pp + 1) == '*')//*匹配
				pp += 2;
			else
				return false;
		}
		else {//*号不在
			if (p.at(pp) == '*')
				return true;
			return false;
		}
	}
	return true;
}

bool isMatch(string s, string p) {
	int s_len = s.length();
	int p_len = p.length();//二者长度
	int sp, pp;//哨兵
	sp = pp = 0;//初始化
	if ((!s.empty()) && (p.empty() || p == ""))return false;
	if (!p.empty() && (s.empty() || s == "")) {
		if (check_pnull(p))return true;
		return false;
	}//去除非法情况和特殊空串情况
	while (sp < s_len || pp < p_len) {
		while ((sp < s_len && pp < p_len) && s.at(sp) == p.at(pp)) {//二者相等就顺着排
			sp++; pp++;
		}//匹配就下行
		//出来有可能是不匹配也有可能是超过长度
		//1不匹配
		if (sp < s_len && pp < p_len) {//确保在长度内
			if (p.at(pp) == '.') {//.类型不匹配
				sp++; pp++;
			}
			else if (p.at(pp) == '*') {//*类型不匹配
				bool real = false;
				int temp_sp = sp - 1;
				//第一种先消去*前面的来跟s匹配
				if (pp + 1 < p_len)//未越界情况才有可能消去,越界一定不用消除
					real= isMatch(s.substr(temp_sp, s_len - temp_sp), p.substr(pp + 1, p_len - pp - 1));
				if (real)return true;
				//第二种到底匹配几个的问题 
				if ((sp < s_len && pp + 1 < p_len)) {//*只匹配一次
					real = isMatch(s.substr(sp, s_len - sp), p.substr(pp + 1, p_len - pp - 1));
					if (real)return true;
				}
				while ((sp < s_len && pp < p_len)) {//从第2此开始依次匹配
					if ((s.at(sp) == p.at(pp - 1)) || p.at(pp - 1) == '.') {
						sp++;
						if ((sp < s_len && pp + 1 < p_len)) {
							real = isMatch(s.substr(sp, s_len - sp), p.substr(pp + 1, p_len - pp - 1));
							if (real)return true;
						}
					}
					else {
						pp++;
						break;
					}
				}
			//	pp++;
			}
			else {
				if ((pp + 1 < p_len) && (p.at(pp + 1) == '*')) {//还有救
					pp += 2;
				}
				else
					return false;
			}

		}
		else {//2超出长度
				//如果二者同时超出了长度则说明匹配成功
				//若是单独一方超出则要看情况
				//a. 若p超出了长度,说明s串还有未比配的数,一定不匹配
				//b. 若s超出了长度,说明要回溯,两种检查,剩下p是否能check_pnull,若能则匹配,若不能则claenOne弄掉一对让s的最后一个字母与剩下的p规则匹配
			if (sp == s_len && pp == p_len) {//二者同时超出了长度则说明匹配成功
				return true;
			}
			else {//单独一方超出
				if (pp >= p_len)return false;//a
				if (sp >= s_len) {//b
					if (p.at(pp) == '*') {//最后超出的p中,pp所在的位置是*
						if (check_pnull(p.substr(pp + 1, p_len - pp))) return true;//剩下的能消除//*从pp + 1开始
						else {//不能消除
							if (clearOne(p.substr(pp - 1, p_len - pp + 1))) {
								sp--;
								pp = pp + 1;
								return isMatch(s.substr(sp, s_len - sp), p.substr(pp, p_len - pp));
							}
							else return false;
						}
					}
					else {//最后超出的p中,pp所在位置不是*
						if (check_pnull(p.substr(pp, p_len - pp))) return true;//剩下的能消除//不是*从pp开始
						else {//不能消除
							if (clearOne(p.substr(pp - 1, p_len - pp + 1))) {
								sp--;
								pp = pp + 1;
								return isMatch(s.substr(sp, s_len - sp), p.substr(pp, p_len - pp));
							}
							else return false;
						}
					}
				}
			}
		}	
	}
	if (sp == s_len && pp == p_len)
		return true;
	else
		return false;
}

int main(void) {

	cout << isMatch("bcbacacbacbbbbcac", "..*a*a*b*c*.*a*bb*.") << endl;
	return 0;
}

 

 

https://bbs.125.la/forum.php?mod=viewthreadtid=14664204 前天搞到现在,终于搞完了。 设计了一种原理和正则有一点相像的表达式,不是匹配文本,而是穷举生成文本 关键字:`\()<>[]{} 1    aa11    字符 2    aA0    裂变元    a依次裂变a,b,c,...z,0依次裂变0,1,2,...9 3    `01-100`    数值过渡    起始-结束,依次是01,02,03,...100,如果起始小于等于结束,递增过渡,否则递减,可以在较小数值前面补0,指定结果最小长度 4    \PI\    回调cha询    用这个关键词去调用回调函数取结果 0    (aa11)    字符组    括号包含的非关键字识别为字符,整个表达式外层默认识别为一个字符组,即外层出现的非关键字默认识别为字符 0    <aA0>    裂变元组    尖括号包含的非关键字识别为裂变元 5    [123]    可选组    两个结果(选或不选),一个空白,一个123 6    {123(444)}    集合单选组    依次是1,2,3,(444) 四种括号可以任意嵌套,里面的内容含义,取决于由内到外的括号链 同层没有优先级,从右到左进行 //如果设计一个互斥组,可以实现m选n,目前不支持,不偏向这个,也没有更多括号了…… //*3~3 示例: qq<00000>    结果:qq00000,qq00001,qq00002,...qq99999的10w个字符串 id`8-80`    结果:id8,id9,id10,...id80 \time\    结果:16:40,如果指定了回调函数,回调函数cha询time,返回了16:40 {123456789}<0000>    结果:10000-99999 {(123)4}[5]    结果:123,4,1235,45 <0aaa>    结果:1个数字开头,后面3个字母到5个字母的所有组合
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值