题目描述
请实现一个函数用来匹配包括.
和*
的正则表达式。模式中的字符.
表示任意一个字符,而*
表示它前面的字符可以出现任意次(包含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: |