1. 题目
2.题目意思
写一个正则表达式出来。
3.代码
解法1:
class Solution:
def isMatch(self, s, p):
s_len = len(s)
p_len = len(p)
if p_len == 0:
return s_len==0 # 如果长度为0,返回s是否长度为0
if p_len > 1 and p[1] == '*': # 如果p的首字母后面是*
return self.isMatch(s, p[2:]) or (s_len !=0 and (s[0]==p[0] or p[0] == '.') and self.isMatch(s[1:], p))
# 1.*表示匹配0个字母,故s和p[2:]继续匹配。 2.s长度不为0,且第一项相等或者p第一项是0(可以匹配任意),并和s[1:]继续匹配(.表示匹配任意多字符或者首项相等匹配多个字母)
else:
return s_len != 0 and (s[0]==p[0] or p[0]=='.') and self.isMatch(s[1:], p[1:])
# 判断长度是否为0且首项相等或者首项为.且继续匹配s[1:]和p[1:]
思路:递归~
如果p[1]
是*
,讨论表示0个或者非0个或者前面是.
。
否则,讨论首项是否相等或者第一项是.
。
细一点,不要漏情况。这种方法时间画的较多。
解法2:
class Solution:
def isMatch(self, s, p):
mem = [[None]*(len(p)+1) for _ in range(len(s)+1)]
# mem[i][j]表示s[0:i]和p[0:j]的匹配情况
# 遍历到最后一位还会往后遍历,所以长度+1防止超过列表索引范围
return self.is_match(s, p ,mem)
def is_match(self, s, p, mem):
s_len = len(s)
p_len = len(p)
if p_len == 0:
return s_len == 0 # p=0,判断s==0
if mem[s_len][p_len] != None: # 记忆化搜索
return mem[s_len][p_len]
if p_len > 1 and p[1] == '*': # 和解法一一样,稍作修改
mem[s_len][p_len] = self.is_match(s, p[2:], mem) or (s_len!=0 and (s[0]==p[0] or p[0]=='.') and self.is_match(s[1:], p, mem))
return mem[s_len][p_len]
else:
mem[s_len][p_len] = s_len != 0 and (s[0]==p[0] or p[0]=='.') and self.is_match(s[1:], p[1:], mem)
return mem[s_len][p_len]
思路:记忆化递归
引入一个列表来记录,减少冗余,速度比解法一快了20多倍~
解法三:
class Solution:
def isMatch(self, s, p):
s_len, p_len = len(s), len(p)
mem = [[False]*(p_len+1) for _ in range(s_len+1)]
mem[0][0] = True
for i in range(s_len+1):
for j in range(1, p_len+1):
if p[j-1] == '*':
mem[i][j] = j>1 and mem[i][j-2] or (i>0 and (s[i-1] == p[j-2] or j>1 and p[j-2] == '.') and i>0 and mem[i-1][j])
else:
mem[i][j] = i>0 and mem[i-1][j-1] and ((i>0 and s[i-1]==p[j-1]) or p[j-1]=='.')
return mem[-1][-1]
思路:dp
对前面的代码稍微改动一下即可,状态转移方程也很好推。
if p[j-1] == '*'
,如果表示0个字母,则dp[i][j]=dp[i][j-2]
;如果同时满足s[i-1]=p[j-2]
或者p[j-2]='.'
,说明匹配到了一个或多个,则dp[i][j]=dp[i-1][j]
。
else
,若s[i-1]=p[j-1]
或者p[j-1]='.'
,则也能匹配,有dp[i][j]=dp[i-1][j-1]
。
从递归入手,由浅入深~
冲冲冲