给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。
‘?’ 可以匹配任何单个字符。
‘*’ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = ""
输出: true
解释: '’ 可以匹配任意字符串。
示例 3:
输入:
s = “cb”
p = “?a”
输出: false
解释: ‘?’ 可以匹配 ‘c’, 但第二个 ‘a’ 无法匹配 ‘b’。
示例 4:
输入:
s = “adceb”
p = “ab”
输出: true
解释: 第一个 ‘’ 可以匹配空字符串, 第二个 '’ 可以匹配字符串 “dce”.
示例 5:
输入:
s = “acdcb”
p = “a*c?b”
输入: false
思路
第一种方法,动态规划,建立数组l
l[a][b]表示p的前a个字符是否配皮s的前b个字符
当p[a]== * 时,因为 * 可以匹配任何字符串,所以只要前半部分能匹配,后面的都行 ,l[a][b]=l[a-1][b] or l[a][b-1 ],在l[a][b]=l[a-1][b]中( * 表示空串),l[a][b]=l[a][b-1]中( * 表示任意字符串 ),两者有一个符合即可
当p[a]== ? 和p[a]==s[b]时,l[a][b]=l[a-1][b-1]
否则不匹配,l[a][b]=0
代码
def isMatch(self, s, p):
l=[]
for i in range(len(p)+1):
l.append([0]*(len(s)+1))
l[0][0]=1
for a in range(1,len(p)+1):
if p[a-1]=='*':l[a][0]=l[a-1][0]
for b in range(1,len(s)+1):
if p[a-1]=='*':
l[a][b]=l[a-1][b] or l[a][b-1]
elif p[a-1]=='?'or p[a-1]==s[b-1]:
l[a][b]=l[a-1][b-1]
else:
l[a][b]=0
return l[-1][-1]!=0
思路
第二种方法(在排行榜上看到的,很巧妙)
遍历p,当遇到时默认其匹配空串,记录其p所匹配s的最后一个字符的位置sr,然后计算p的后半部分是否能匹配s的后半部分,如果不能便使sr+1,使 * 多匹配一个字符,再重新计算,直到成功。
只用记录最后一个 * 的位置,及其所匹配的最后一个字符的位置即可
以
‘adcaeb’
’ * a b’
为例
当第二个 出现时,第一个 便不用考虑*,因为 * a *能匹配的字符 * 也全都能匹配 , * a *是 * 的一个子集,只要能遍历到第二个 * ,前面的都不用考虑了, * a * 直接看做 * 即可,前提是遍历的到第二个 *,用’ * z * b‘便遍历不到第二个
考虑一种特殊情况,p的前半部分匹配完了s,后面有一堆多余的 **
将其全部视为空串
代码
si记录s遍历的位置
pi记录p遍历的位置
sr记录遇到的最后一个 * 匹配的字符的位置
pr记录遇到的最后一个 * 的位置
def isMatch(self, s, p):
si,pi,pr,sr=0,0,-1,-1
while si<len(s):
if pi<len(p) and p[pi]=='*':
pi+=1
pr=pi
sr=si
elif pi<len(p) and (p[pi]=='?' or p[pi]==s[si]):
pi+=1
si+=1
elif pr!=-1:
pi=pr
sr+=1
si=sr
else:
return False
while(pi<len(p) and p[pi]=='*'):
pi+=1
return pi==len(p)