题解
递归
递归函数 i s M a t c h ( s , p ) isMatch(s,p) isMatch(s,p), s s s表示待匹配字符, p p p表示字符规律
- 若 p p p为空,此时返回 s s s是否为空。表示若字符规律已经为空,若 s s s还不为空,此时匹配失败。若为空,表示匹配成功。
- 定义 p r e pre pre表示 s s s和 p p p第一位是否匹配成功。 匹配条件: s s s不能为空且 p [ 0 ] = = s [ 0 ] o r " . " p[0]==s[0]\ or\ "." p[0]==s[0] or "."。表示 p p p的第一位等于 s s s的第一位,或者 p [ 0 ] = = " . " p[0]=="." p[0]=="."可以匹配所有字符。
- 若
p
p
p中有
∗
*
∗字符,条件
l
e
n
(
p
)
>
=
2
a
n
d
p
[
1
]
=
=
∗
len(p)>=2\ and\ p[1]==*
len(p)>=2 and p[1]==∗,表示第二位为
∗
*
∗。即有字符和
∗
*
∗相连。对应两种情况。
- 跳过这两个字符,表示这个字符出现零次。即 i s M a t c h ( s , p [ 2 : ] ) isMatch(s,p[2:]) isMatch(s,p[2:])—此处不理解,看我的注意!
- 首位匹配成功,继续匹配 s [ 1 : ] s[1:] s[1:]和 p p p,即 p r e a n d i s M a t c h ( s [ 1 : ] , p ) pre\ and\ isMatch(s[1:],p) pre and isMatch(s[1:],p)
- 若无 ∗ * ∗则,继续匹配,返回 p r e a n d i s M a t c h ( s [ 1 : ] , p [ 1 : ] ) pre\ and\ isMatch(s[1:],p[1:]) pre and isMatch(s[1:],p[1:])
注意!
字符
+
∗
+*
+∗是一个整体,表示这个字符出现0次或者多次! 经过我的测试,测试用例*不能单独出现,一定跟在字符后
如下两种测试用例,前一种会报错,后一种不会。
复杂度分析
- 时间复杂度: O ( ( S + P ) ∗ 2 S + P 2 ) O\left((S+P)*2^{S+\frac{P}{2}}\right) O((S+P)∗2S+2P),具体分析略。 S S S表示 s s s的长度, P P P表示 p p p的长度。
- 空间复杂度: O ( ( S + P ) ∗ 2 S + P 2 ) O\left((S+P)*2^{S+\frac{P}{2}}\right) O((S+P)∗2S+2P)
Python
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if not p:
return not s
first = bool(s) and p[0] in {s[0], '.'}
if len(p) >= 2 and p[1] == '*':
return self.isMatch(s, p[2:]) or first and self.isMatch(s[1:], p)
else:
return first and self.isMatch(s[1:], p[1:])
Java(待完成)
动态规划法
重叠子问题结构
-
初始化 s s s的长度 S S S, p p p的长度 P P P
-
初始化哈希表 m e m o = { } memo=\{\} memo={},键为 ( i , j ) (i,j) (i,j),值为 T r u e o r F a l s e True\ or\ False True or False,表示 s [ 0 , . . . , i ] s[0,...,i] s[0,...,i]和 p [ 0 , . . . , j ] p[0,...,j] p[0,...,j]是否匹配。
-
定义递归函数 d p ( i , j ) dp(i,j) dp(i,j), i i i为当前 s s s的匹配位置, j j j为 p p p的匹配位置。
- 若 ( i , j ) (i,j) (i,j)出现在 m e m o memo memo中,表示当前子问题,之前已经处理过,直接返回对应的值, m e m o [ ( i , j ) ] memo[(i,j)] memo[(i,j)]
- 若 j = = P j==P j==P,说明 p p p已经匹配完,若此时 s s s还有字符未匹配,则返回 F a l s e False False,若 s s s也匹配完,则返回 T r u e True True。即返回 i = = S i==S i==S
- 定义 p r e pre pre表示当前 p p p和 s s s的首位是否匹配。条件: i < S i<S i<S表示 s s s是否遍历完。且 p [ j ] p[j] p[j]是否等于 s [ i ] s[i] s[i]或 " . " "." "."。 p r e = i < S a n d p [ j ] i n { s [ i ] , " . " } pre= i<S\ and\ p[j]\ in\ \{s[i],"."\} pre=i<S and p[j] in {s[i],"."}。
- 判断是否存在
∗
*
∗字符,条件:
j
<
=
P
−
2
j<=P-2
j<=P−2表示是否还剩两个字符以上,且
p
[
j
+
1
]
p[j+1]
p[j+1]为
∗
*
∗:
- 跳过这两个字符,表示匹配 0 0 0次, d p ( i , j + 2 ) dp(i,j+2) dp(i,j+2)
- 首位匹配成功,继续匹配下一位, p r e a n d d p ( i + 1 , j ) pre\ and\ dp(i+1,j) pre and dp(i+1,j)
- t m p = d p ( i , j + 2 ) o r p r e a n d d p ( i + 1 , j ) tmp=dp(i,j+2)\ or\ pre\ and\ dp(i+1,j) tmp=dp(i,j+2) or pre and dp(i+1,j)
- 否则, t m p = d p ( i + 1 , j + 1 ) tmp=dp(i+1,j+1) tmp=dp(i+1,j+1)
- 更新 m e m o memo memo, m e m o [ ( i , j ) ] = t m p memo[(i,j)]=tmp memo[(i,j)]=tmp
- 返回 t m p tmp tmp
-
返回 d p ( 0 , 0 ) dp(0,0) dp(0,0)
复杂度分析
- 时间复杂度: O ( S ∗ P ) O\left(S*P\right) O(S∗P)
- 空间复杂度: O ( S ∗ P ) O(S*P) O(S∗P)
Python
class Solution:
def isMatch(self, s: str, p: str) -> bool:
S=len(s)
P=len(p)
memo={}
def dp(i,j):
if((i,j) in memo):
return memo[(i,j)]
if(j==P):
return i==S
pre=i<S and p[j] in {s[i],"."}
if(j<=P-2 and p[j+1]=="*"):
tmp=dp(i,j+2) or pre and dp(i+1,j)
else:
tmp=pre and dp(i+1,j+1)
memo[(i,j)]=tmp
return tmp
return dp(0,0)