正则表达式的匹配计算

题目描述
请实现一个函数用来匹配包括.和✳的正则表达式。模式中的字符’.'表示任意一个字符,而✳表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab✳ac✳a"匹配,但是与"aa.a"和"ab✳a"均不匹配
题意解析
可能这个题目比较绕,直接看不容易看懂,下面我先把题目的意思分析一下,捋清思路。
node1:字符串是被动对象,要用来与模板进行匹配
node2:正则表达式在题目中给出了.和✳,.只匹配一个字符,且可以充当任何字符进行匹配;*可以匹配0至多个字符
解题分析
step.1:首先考虑两个字符串都为空的情况,结果肯定能够实现匹配
step.2:然后考虑字符串不为空,但是模板为空的情况,肯定不能够实现匹配
step.3:如果程序能执行到这,说明前两点都不符合,这时要考虑模板中仅有.的情况
该过程从头将字符串与模板挨个字符进行比较,如果两字符相等就继续比较下一个,如果模板中有.也继续比较下一个,当字符串为空时表明全匹配上。否则就没有完成匹配。
step.4模板中含有✳,有没有.不重要。由于✳出现的时候不确定表示的时它前面字符重复的0次或者是1次至多次,因此又要分为两种情况:
(1):✳表示它前面出现字符重复0次,重复0次的含义就是✳和它前面的字符不存在,这时模板就少了两个字符
(2):✳表示它前面的字符出现1次或者多次,这样的话需要将字符串中的字符每次往后取出一个与之比较。
鉴于对上述的分析,题目可以使用两种方法解决得到,第一种是递归,第二种就是动态规划,首先来分析一下递归,以及它的出口条件。
递归方法分析
设字符串为s,长度为sn;模板为p,长度为pm。对于p的第i位,有正常字符,.和✳三种情况。
(1)p[i]为正常字符,只需要比较(s[i]=p[i])是否成立,如果成立且两个串都不为空继续比较下一次,设递归函数为dfs,则执行dfs(s[i+1],p[i+1]),到i=sn或者pm的时候结束
(2)p[i]=.,因为.可以匹配任意字符,因此只需要比较dfs(s[i+1],p[i+1])即可
(3)如果p[i]=✳,表明p[i-1]存在0或者多次,如果存在0次时,比较s[i]和p[i+2]
如果存在1次或者多次,比较s[i+1]和p[i]。
下面根据递归的逻辑,把代码设计一下

class Solution {
public:
    bool match(char* str, char* pattern)
    {
        //两个串都是空的
        if(*str=='\0'&&*pattern=='\0')return true;
        //如果模板是空串而匹配对象非空
        if(*str!='\0'&&*pattern=='\0')return false;
        //如果两个串不存在为空的情况,正式进行比较,先看最简单的只有.的情况
        //这个地方需要注意一下,如果p[i]为*,且表示*前面的字符出现0次,那么我们在对s[i-1]和p[i-1]比较时,比较的结果就失效了,为了避免这种情况,我们需要判断p[i+1]是不是*,这样就不会出现这个问题
        if((*(pattern+1))!='*'){
            //对应位置是否相等,或者为.
            //条件一str!='\0'是为了保证str能够匹配完,只要是pattern先比较完,那一定不匹配,这个地方不矛盾
            if(*str!='\0'&&(*str==*pattern||*pattern=='.'))return match(str+1, pattern+1);
            else
                return false;
        }
        //模板里面有*的情况
        else{
            //两种情况
            //*表示0个匹配的时候,直接模板+2后的位置与字符串当前位置进行比较
            bool rest=false;
            //表示的是*表示它前面一个或者多个字符重复时的情况
            if(*str!='\0'&&(*str==*pattern||*pattern=='.'))rest=match(str+1, pattern);
            //*表示0个字符的情况
            //由于不知道具体表示了几个,因此取两者的或,只要满足一个即可
            return rest||match(str, pattern+2);
        }
    }
};

下面分析一下动态规划是如何实现的
如果前面的分析都能明白,那动态规划就好理解一点了
动态规划涉及到二维向量的使用,这个不明白的可以去我的博客里面找一下,有一篇是专门详细的介绍向量的使用的。
动态规划是一个自底向上的过程,正好与递归相反
设vec[i][j]表示str的前i个和pattern的前j个能够匹配。
则vec[0][0]=1
vec[1…sn][0]=0
对于为.的情况,vec[i][j]=vec[i-1][j-]
对于有✳的情况分为两种:
(1)✳表示0重复:vec[i][j]=vec[i][j-2]
(2)✳表示1或者多重复,vec[i][j]=vec[i-1][j]
代码如下:

class Solution{
	public:
	bool match(char *s,char *p){
		//求出两个字符串的长度,定义二维向量时的长度要使用两个字符串的长度
		int sn=strlen(s);
		int pn=strlen(p);
		//定义一个二维向量
		vector<vector<char>> f(sn+1,vector<char>(pn+1,0));
		for(int i=0;i<=sn;i++){
			for(int j=0;j<=pn;j++){
				//j=0时,i=0,f[i][j]=1,否则都为0
				if(j==0)f[i][j]=(i==0);
				else{
					//没有*的情况
					if(p[j-1]!='*'){
						if(i>=1&&(s[i-1]==p[j-1]||p[j-1]=='.'))f[i][j]=f[i-1][j-1];
					}
					//有*的情况
					else{
						if(j>=2)f[i][j]|=f[i][j-2];
						if(i>=1&&(s[i-1]==p[j-1]||p[j-1]=='.'))f[i][j]|=f[i-1][j];
					}
				}
			}
		}
		return f[sn][pn];
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是小峰呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值