递归
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if not(s or p): # 两个同时为空
return True
elif not s and p: #s空了p没空
if p[0]=="*":
return self.isMatch(s[0:],p[1:])
else:
return False
elif not p and s: #p空了s没空
return False
if s[0]==p[0] or p[0]=="?": #不涉及*的匹配
return self.isMatch(s[1:],p[1:])
elif p[0]=="*":
return self.isMatch(s[1:],p[0:]) or self.isMatch(s[0:],p[1:])
else:
return False
这个超时了
递归-改
class Solution:
dp={}
def del_star(self,p): #去除多余星号
i=0
while i< len(p)-1:
if p[i]==p[i+1]=="*":
p=p[:i+1]+p[i+2:]
i-=1
i+=1
return p
def helper(self,s,p):
if (s,p) in self.dp: # 先进行查询
return self.dp[(s,p)]
if s==p or p=="*": # 两个相等,或p只有一个*
self.dp[(s,p)]=True
elif s=="" or p=="": # 存在一个为空
self.dp[(s,p)]=False
elif s[0]==p[0] or p[0]=="?": #不涉及*的匹配
self.dp[(s,p)]=self.helper(s[1:],p[1:])
elif p[0]=="*":
self.dp[(s,p)]=self.helper(s[1:],p[0:]) or self.helper(s[0:],p[1:])
else:
self.dp[(s,p)]=False
return self.dp[(s,p)]
def isMatch(self, s: str, p: str) -> bool:
p=self.del_star(p)
return self.helper(s,p)
看了题解的思路写的,相较于之前的递归,有两个改进的地方
- 定义了del_star函数来解决多个*号并列而导致多次无用递归的问题
- 定义了dp变量来储存之前出现过的情况,从而减少了重复运算的情况
看题解里面说,用记忆的方法是优化递归的标准方法,这是我应该学习的
执行用时 :1704 ms, 在所有 Python3 提交中击败了6.11%的用户
内存消耗 :761.7 MB, 在所有 Python3 提交中击败了5.16%的用户
回溯
class Solution:
dp={}
def del_star(self,p): #去除多余星号
i=0
while i< len(p)-1:
if p[i]==p[i+1]=="*":
p=p[:i+1]+p[i+2:]
i-=1
i+=1
return p
def isMatch(self, s: str, p: str) -> bool:
p=self.del_star(p)
p_len=len(p)
s_len=len(s)
p_start=s_start=-1
j=i=0 #j遍历s,i遍历p
while j<s_len:
if p_len>i and (p[i]==s[j] or p[i]=="?"):
i+=1
j+=1
elif p_len>i and p[i]=="*":
s_start=j
p_start=i
i+=1
elif p_start==-1:
return False
else:
i=p_start+1
j=s_start+1
s_start=j
return p[i:]=="*" or not p[i:]
看题解的。用双指针来遍历两个列表
在第一次遇到之前没遍历过的星号时,把p_start记作该点,当作回溯的点,并且把s_start也记作该点,当作回溯时s数组开始的点。记录完之后就先假设星号匹配0个字符,继续编历下区
当遇到 p数组遍历完了但s数组还有 或者两个对应字符不相同的情况时,进行检验,如果之前没有星号,说明匹配不可能成功,如果之前有过星号(也就是start!=-1的时候)回溯到那个点,然后j再往后移一位(也就是星号匹配的字符数增多一位)然后继续遍历
有一点是我刚开始看的时候没看懂的。为什么只回溯最近的点,而之前的点不去管了?我个人的理解是:假设匹配模式是aaa*bb*cccc,如果start已经设为第二个星号了,并且,无论星号匹配多少个字符,都无法满足使最后的cccc匹配成功,那么也就说明了字符串末尾不具有cccc这个子串。从这个基础上来看,就算回溯到了第一个星号,那么不管那个星号匹配多少个字符,依旧无法使cccc匹配成功。因此,不需要回溯到之前的点了。
执行用时 :64 ms, 在所有 Python3 提交中击败了86.70%的用户
内存消耗 :13.6 MB, 在所有 Python3 提交中击败了82.47%的用户