题目描述
请实现一个函数用来匹配包括.和*的正则表达式。模式中的字符.表示任意一个字符,而*表示它前面的字符可以出现任意次(包含0次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串aaa与模式a.a和ab*ac*a匹配,但是与aa.a和ab*a均不匹配
关于模式匹配:
- 一条包括
.和*的正则表达式,即模式,可以用非确定有限状态机来阐述。可知比较麻烦的是处理*。ba*ab.的状态机来举例,状态s1是初始状态,收到b进入s2,s2收到a有两个选择,可能回到s2,也可能进入新状态s3,s3收到b进入s4,s4收到任意一个字符进入s5。
- 用递归。
关于如下代码:
- 根据是否处理
*分为前后两部分,后者是第二个字符是*这一种情况,前者包括s为空、无.和*的参与和.后面没有*这三种情况。而前者根据是否处理.又分为.后面没有*这种情况,以及s为空、无.和*的参与这种情况。四种类别互斥且完备,如下树状图所示。
1 | p为空 |
- 处理部分只主动返回True,为确保返回的是True而非False,在返回之前有确认逻辑。坚持不返回False,因为不知为不知,以确保四分支处理线互不干扰。最后一行有个返回False,可以认为是被动返回。
- 返回True的确认逻辑的match函数,其输入参数s和p的变更要有依据。如
无.和*的参与部分里参数变更为s[1:], p[1:],是因为有s[0] == p[0];而第二个字符是*部分里参数变更为s, p[2:],是因为有p[1] == '*'。
1 | class Solution: |
- 动态规划。
长度为x的字符串\(s_1s_2\cdots
s_x\),模式长度为y的模式序列\(p_1\cdots
p_y\)。如字符串aaa的长度是3,而模式序列ab*ac*a有5个子模式a,b*,a,c*,a。令g(x,y)表示\(s_1s_2\cdots s_x\)与\(p_1\cdots
p_y\)的匹配状态,如g(x,y)=0表示匹配不成功,g(x,y)=1表示匹配成功。
则g(x,y)有如下递推关系:
- 如果\(p_y\)不是带
*子模式,有g(x,y) = g(s_x, p_y) and g(x-1,y-1)。其中\(g(s_x, p_y)\)表示字符\(s_x\)与模式\(p_y\)的匹配状态,很容易计算。特殊的,有g(0,y)=g(0,p_y)=1 if y>=1,以及g(x,0)=g(s_x,0) if x>=1。 - 如果\(p_y\)是带
*子模式,有g(x,y)=g(x,y-1) or g(s_x,s_y) and g(x-1,y)。其中,g(x,y-1)=1则说明去掉\(p_y\)仍匹配,即\(p_y\)匹配0个字符。而g(s_x,s_y)& g(x-1,y)=1则说明\(p_y\)匹配一个或多个字符。特殊的,有g(0,y)=g(0,y-1) if y>=1 g(0,?)和g(?,0)分别表示空模式和空字符串。- 边界值
g(0,0)=1 - g(x,y)组成一个维度为
(x+1)*(y+1)的二维矩阵。
1 | class Solution: |