https://leetcode.com/problems/regular-expression-matching/description/
题目大意:给一个字符串s和模式串p,求s是否匹配p
这里要注意的是“*”表示前面的字符可以重复0到无数次,并不是传统意义上的通配符。
解题思路1(递归):把x*
(x为任意字符),当做一个整体,这是最难处理的部分,因为x可以重复0到无数次。
我们先来判断p是否为空,若为空则根据s的为空的情况返回结果。当p的第二个字符为*
号时,由于*
号前面的字符的个数可以任意,可以为0,那么我们先用递归来调用为0的情况,就是直接把这两个字符去掉再比较,或者当s不为空,且第一个字符和p的第一个字符相同时,我们再对去掉首字符的s和p调用递归,注意p不能去掉首字符,因为*
号前面的字符可以有无限个;如果第二个字符不为*号,那么我们就老老实实的比较第一个字符,然后对后面的字符串调用递归
代码:
class Solution:
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
if not p:
return not s
#为了使代码简洁,第一位字符匹配的结果用first_match代替
first_match = bool(s) and (s[0] == p[0] or p[0] == '.')
if len(p) >= 2 and p[1] == '*': #如果在p中检测到“x*”型字段
return self.isMatch(s, p[2:]) or first_match and self.isMatch(s[1:], p)
else:
return first_match and self.isMatch(s[1:], p[1:])
解题思路2(DP):
用二维矩阵dp记录,dp[i][j]
的布尔值表示s[0..i)
是否与p[0..j)
匹配(注意右边是开区间),初始值为False。
初始状态:令dp[0][0]
为true,i=0表示s为空,j=0表示p为空,s、p都为空的时候是匹配的。
重点还是处理x*
类型的p串:
例如
判断“a”和“aa*”是否匹配
s=“a a a” , i=1(注意前面表述是开区间)
^
p=“a a *” , j=3
^
若1)a*
匹配0次,则j回退两位,i不动:
s=“a a a” , i=1
^
p=“a a *” , j=1
^
若“a”和“a”匹配,则“a”和“aa*”匹配。
即dp[i][j]的状态和dp[i][j-2]是相同的,推导得dp[i][j] = dp[i][j-2]
判断“aa”和“aa*”是否匹配
s=“a a a” , i=2
^
p=“a a *” , j=3
^
2)a*
匹配1次,则i回退1位,j回退2位
s=“a a a” , i=1
^
p=“a a *” , j=1
^
若“a”和“a”匹配,且“a”和“aa*”匹配,则“aa”和“aa*”匹配。
“a”和“a”匹配的条件为:s[i-1] == p[j-2] ,或p[j-2] == ‘.’(单个字符匹配)
“a”和“aa*”匹配的条件:有点抽象,因为a*
可以匹配0到无数个a,因此要保证上一个状态是匹配的(j指向*,不动;i回退一位),当前状态才能匹配。上一个状态为:dp[i-1][j] = true
综上,a*匹配一次的条件:
dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.')
1)和2)情况是并列的。
3)单个字符匹配:
两种,一种是相等匹配,另一种是‘.’匹配。而且上一个状态dp[i-1][j-1]匹配
条件:
dp[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.')
此外还要注意下标,要保证i>0
因为有p[j-1] == ‘*’的限制,因此j不用过多限制
i从0到m
j从1到n,因为j=0时p为空串,除了空以外的所有s都不匹配
class Solution:
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
m,n = len(s), len(p)
dp = [[False] * (n+1) for _ in range(m+1)]
dp[0][0] = True
for i in range(m+1):
for j in range(1, n+1):
if p[j-1] == '*':
dp[i][j] = dp[i][j-2] or (i>0 and dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.'))
else:
dp[i][j] = i>0 and dp[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.')
print(dp)
return dp[m][n]