正则表达式匹配

题目描述

在这里插入图片描述
在这里插入图片描述

动态规划解法

1. dp数组的定义

设m为s的大小,n为p的大小,因为要考虑空串""的匹配情况,所以dp数组应该是(m+1)*(n+1)。dp数组形式如下:

dp数组“”p[0]p[1]p[2]p[j]p[n]
“”
s[0]
s[1]
s[2]
s[i]
s[m]

dp[i][j]表示s[0...i-1]p[0...j-1]是否能够匹配上,匹配为true,不匹配就为fasle

2. 状态转移方程

dp[i][j]的值为true还是false,取决于s[0...i-1]p[0...j-1]能否匹配,就必须考虑当前正在遍历的s[i-1]p[j-1]

p[j-1]'a-z''.''*'三种可能的值,前两种都容易分析,就是这个'*'较为麻烦,它与前一个字符共同作用,而且可以匹配任意次数。所以我们以p[j-1]是不是'*'分情况讨论。

  1. p[j-1] != *

1.1 p[j-1] == '.'
'.'可以匹配任意字符,所以此时不管s[i-1]为何值,s[i-1]p[j-1]都是匹配的。那么这时s[0...i-1]p[0...j-1]能否匹配,就取决于s[0...i-2]p[0...j-2],所以dp[i][j] = dp[i-1][j-1]

1.2 p[j-1] == 'a-z'

1.2.1 p[j-1] == s[i-1]
这种情况下,s[i-1]p[j-1]都是匹配的。那么这时s[0...i-1]p[0...j-1]能否匹配,就取决于s[0...i-2]p[0...j-2],所以dp[i][j] = dp[i-1][j-1]

1.2.2 p[j-1] != s[i-1]
这种情况下,s[i-1]p[j-1]是不匹配的,所以dp[i][j] = fasle

  1. p[j-1] == *,此时主要看与*搭配的字符,即p[j-2]

2.1 p[j-2] == 'a-z'并且p[j-2]==s[i-1]
这种情况下,这对儿x*是可以匹配的,要考虑匹配几次(0、1、多)。
如果匹配0次,那么s[0...i-1]p[0...j-1]能否匹配,就取决于s[0...i-1]p[0...j-3]能否匹配,所以dp[i][j] = dp[i][j-2]
如果要匹配大于0次,那么s继续往后走,p暂时不动。所以此时s[0...i-1]p[0...j-1]能否匹配,就取决于s[0...i-2]p[0...j-1]能否匹配,即dp[i][j] = dp[i-1][j]
所以最后,这种情况下,dp[i][j] = dp[i-1][j] || dp[i][j-2]

2.2 p[j-2] == 'a-z'但是p[j-2]!=s[i-1]
这种情况下,*只能匹配0次,即这对儿x*作废,所以此时s[0...i-1]p[0...j-1]能否匹配,就取决于s[0...i-1]p[0...j-3]能否匹配,所以dp[i][j] = dp[i][j-2]

2.3 p[j-2] == '.'
p[j-2]p[j-1].*。这种情况可以与2.1视为同一种情况,即dp[i][j] = dp[i-1][j]

3. dp数组初始化

  1. 空s

    1.1 空p
    s=""p=""是可以匹配的,即空s可以匹配空p,因此dp[0][0]=true

​ 1.2 非空p
s=""和非空的p是有可能匹配的,即p="x*y*z*"这种形式。所以,当1<=j<n时,

1.2.1 若p[j-1] != '*',即p[j-1]'.''a-z',此时是不匹配的,所以dp[0][j]=false

​1.2.2 若p[j-1] == '*',因为*可以匹配0次,所以这个*可以和前边一个位置的字符消掉,即p[j-1]p[j-2]不影响dp[0][j]的值。所以这种情况下,dp[0][j]=dp[0][j-2]

  1. 空p
    ​ 2.1 空s
    ​ 同3.1.1

​ 2.2 非空s
p=""不可能和任何非空的s匹配成功,所以dp[i][0]=0

  1. 非空s与非空p
    ​ 需要经过转移计算

初始化结果

经过上述步骤,dp数组应初始化为如下形式:

dp数组“”p[0]p[1]p[2]p[j]p[n]
“”100或者dp[0][j-2]0或者dp[0][j-2]0或者dp[0][j-2]0或者dp[0][j-2]0或者dp[0][j-2]0或者dp[0][j-2]
s[0]0
s[1]0
s[2]0
0
s[i]0
0
s[m]0

注:

  1. dp[0][1]一定为false。因为题目保证出现*时,前边都有有效的字符与之匹配,即不可能是p[0]一定不是*
  2. j>=2时,dp[0][j]的值需要按照3.1.2进行判断,有0或者dp[0][j-2]两种可能。

4. 遍历顺序

显然是正序遍历

5. 返回形式

​ 题目要求s[0...m-1]p[0...n-1]能否匹配所以应该返回dp[m][n]

完整代码

bool isMatch(string s, string p) {
	const int m = s.size();
    const int n = p.size();
	vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
	//初始化
	dp[0][0] = 1;
    for(int i = 1; i <= m; ++i){
		dp[i][0] = 0;
    }
	for(int j = 1; j <= n; ++j){
		p[j-1] == '*' ? dp[0][j] = dp[0][j-2] : dp[0][j] = 0;
	}
	//状态转移(遍历)
	for(int i = 1; i <= m; ++i){
		for(int j = 1; j <= n; ++j){
			if(p[j-1] != '*'){
				if(p[j-1] == s[i-1] || p[j-1] == '.'){
					dp[i][j] = dp[i-1][j-1];
				}
				else{
					dp[i][j] = false;
				}
			}
			else{
				if(p[j-2] == s[i-1] || p[j-2] == '.'){
					dp[i][j] = dp[i-1][j] || dp[i][j-2];
				}
				else{
					dp[i][j] = dp[i][j-2];
				}
			}
		}
	}
	return dp[m][n];
}
  • 23
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

极客熊猫GeekPanda

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

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

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

打赏作者

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

抵扣说明:

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

余额充值