给定一个字符串 (s) 和一个字符模式 §。实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符。
‘*’ 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:
思路1:递归
class Solution:
def isMatch(self, s: str, p: str) -> bool:
# 若p为空,返回s是否为空
# 若p为空,s不为空,匹配失败;s为空,匹配成功
if not p:
return not s
# 定义first表示p和s的第一位是否匹配成功,匹配条件为p,s不为空 and p[0]==s[0]或“.”
# 函数bool(s) 用于将给定参数s转换为布尔类型,如果没有参数,返回 False
first = bool(s) and p[0] in {s[0], '.'}
# 若p有*(p的长度>=2,p[1]==“*”,说明p的第二位是*,且*前有字符与之匹配)
if len(p)>=2 and p[1] == "*":
# 两种情况:
# 第一:跳过这两个字符,x*表示x这个字符出现了0次(即没有字符x)
# 第二:首位匹配成功,继续匹配s[1:]和p,即返回first and isMatch(s[1:],p[1:])
return self.isMatch(s,p[2:]) or pre and self.isMatch(s[1:], p)
else:
return first and self.isMatch(s[1:],p[1:])
思路2:动态规划
class Solution:
def isMatch(self, s: str, p: str) -> bool:
# 初始化sss的长度S,ppp的长度P
S = len(s)
P = len(p)
# 初始化哈希表memo = {}
memo = {}
# memo键为(i,j),值为True or False,表示s[0, ..., i]和p[0, ..., j]是否匹配
# 定义递归函数dp(i, j),i为当前s的匹配位置,j为p的匹配位置。
def dp(i, j):
# 若(i,j)出现在memo中,表示当前子问题,之前已经处理过,直接返回对应的值,memo[(i,j)]
if ((i, j) in memo):
return memo[(i, j)]
# 若j == P,说明p已经匹配完,若此时s还有字符未匹配,则返回False,若s也匹配完,则返回True。即返回i == S
if (j == P):
return i == S
# 定义pre表示当前p和s的首位是否匹配。条件:i < S 表示s是否遍历完。且p[j]是否等于s[i]或"."。
pre = i < S and p[j] in {s[i], "."}
# 判断是否存在 * 字符,条件:j <= P−2表示是否还剩两个字符以上,且p[j + 1]为 *:
if (j <= P - 2 and p[j + 1] == "*"):
# 跳过这两个字符,表示匹配0次,dp(i,j+2) 或者 首位匹配成功,继续匹配下一位
tmp = dp(i, j + 2) or pre and dp(i + 1, j)
else:
# 否则,tmp=dp(i+1,j+1)
tmp = pre and dp(i + 1, j + 1)
# 更新memo,memo[(i, j)] = tmp
memo[(i, j)] = tmp
# 返回tmp
return tmp
# 返回dp(0, 0)
return dp(0, 0)