通配符匹配
题目描述:
解题思路:
- 第一种:递归。按照顺序,依次判断是否为
*
,因为*
能代表多个不同的字符。每次判断完p
都会通过切片的方式去掉判断完的字符,然后进行递归。最后剩下最后一个字符的时候判断是否为*
,如果是则直接返回True
,如果不是,则要判断最后这个字符和s[0]
要对应相等或者最后一个字符为?
。 - 因为这个方法函数调用过深,会超时,所以需要换一种方法。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if not p:
return not s
if len(p) == 1:
if p[0] == '*':
return True
else:
return len(s) == 1 and (p[0] == s[0] or p[0] == "?")
if p[0] != "*":
if not s:
return False
else:
return (p[0] == s[0] or p[0] == "?") and self.isMatch(s[1:], p[1:])
else:
while s:
if self.isMatch(s, p[1:]):
return True
s = s[1:]
return self.isMatch(s, p[1:])shidoune
- 第二种:动态规划。首先建立动态规划模型
dp
,先全部默认赋给False
,并且这个dp
是以s
字符串作为列,以p
作为行,所以dp[0][0]
就是当字符串s
和p
均为空的情况,所以改成True
。 - 首先先是判断当
s
字符串为空时,p
字符串的前i
项是否能匹配,如果p
的这一次对应的项是*
,则看它前一项是否匹配,如果匹配,则为True
,所以当前项也为True
。如果不匹配,则后面也都为False
。当然,这里我们不去填s
非空,p
为空的情况,因为这样会刚好符合默认情况,也就是全为False
。 - 接下来,我们开始填写
dp
动态规划表。我们依次遍历两个字符串,当出现相同项,或者p
字符串的对应字符为?
,则说明当前对应字符已匹配,且要求各往后一位也匹配。如果当前p
字符串位置字符为*
,则说明有三种情况,满足其一就说明匹配:1)代表空字符串。2)代表任意一个字符,也就是当前对应的。3)代表多个任意的字符。如果遍历中没有碰到相同项,则说明当前这两个字符串不匹配,就继续保持默认False
。最后我们判断dp[-1][-1]
是否匹配,这个也就是dp[len(p)][len(s)]
,即最终两个总字符串p
和s
是否匹配。将这个结果返回就是最终的答案。 - 时间复杂度:O(SP)
class Solution:
def isMatch(self, s: str, p: str) -> bool:
s_len = len(s)
p_len = len(p)
dp = [[False] * (s_len+1) for _ in range(p_len+1)]
dp[0][0] = True
for i in range(p_len):
if p[i] == '*':
dp[i+1][0] = dp[i][0]
for j in range(p_len):
for k in range(s_len):
if p[j] == s[k] or p[j] == '?':
dp[j+1][k+1] = dp[j][k]
elif p[j] == '*':
dp[j+1][k+1] = dp[j][k+1] or dp[j+1][k] or dp[j][k]
return dp[-1][-1]
-
第三种:回溯法。这个方法我也是看了好久,也是个很好的方法,运行速度很快,需要好好总结学习。大体思路和动态规划很类似,只是写法上的不同。
-
分别定义搜索
s
和p
的双指针s_index
和p_index
、记录*
号出现的位置的star_index
和p
中从头能匹配到的位置s_match
。 -
首先判断
s
字符串不为空时,从每个字符串的第一个字符开始匹配,如果匹配了,就看是验证下一个。如果p
中字符为*
,则记录下来出现位置给star_index
,并且记录此时的s
位置给s_match
。然后如果*
的位置不是在末尾处,则继续判断p
的下一位是否匹配,然后s
的判断的起始位置为s_match
的下一个位置,其中s_match
一直加1
就是为了找到能和star_index
的下一个位置匹配的。如果一直都没有出现能匹配的,且s[s_index]
和p[p_index]
已经不匹配了,所以返回False
。 -
循环结束之后,也就是
s
字符串全部匹配完成,如果刚好字符串p
指针到最后一个元素了,则说明p
也刚好匹配完成,返回True
。但是如果p
字符串还有剩余字符未匹配,则就要判断剩余的字符是否为*
,因为如果这种情况要使得匹配成功,p
字符串后面的这些字符必须要表示为空字符,而有这个能力的字符就是*
,所以只有后面的字符都为*
,才能使得两个字符串匹配。最后循环完成之后,如果p_index
指向字符串p
末尾,说明匹配完成,返回True
。否则,匹配失败,返回False
。 -
时间复杂度:O(SlogP)
class Solution:
def isMatch(self, s: str, p: str) -> bool:
s_len, p_len = len(s), len(p)
s_index, p_index, star_index, s_match = 0, 0, -1, 0
while s_index < s_len:
if p_index < p_len and (p[p_index] == s[s_index] or p[p_index] == "?"):
s_index += 1
p_index += 1
elif p_index < p_len and p[p_index] == "*":
star_index = p_index
p_index += 1
s_match = s_index
elif star_index != -1:
p_index = star_index + 1
s_match += 1
s_index = s_match
else:
return False
while p_index < p_len and p[p_index] == "*":
p_index += 1
return p_index == p_len