Wildcard Matching
题目描述
Implement wildcard pattern matching with support for '?'
and '*'
.
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char *s, const char *p)
Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
解题方法
backtracking + dfs
和regular expression的做法差不多,转变一下*
的处理情况
DP
首先我们想到这一题和regular rexpression matching差不多,也可以用DP来解,主要就是将"*"的情况改变一下
two pointer
上面两种做法都过不了leetcode,因为time limit和stack limit,我们只能另想办法。看了各路大神的解法,找到了将
recursive改为two-pointer的做法,思路还是遇到*
时不断从0个开始往后试探匹配,如果不行的话就回朔,关键就是
回朔时候的pointer reset到哪里的问题。
pointer reset到哪里的问题
- 首先我们有两个pointer分别对应
s
和p
当处理*
时,我们需要从匹配0个开始不断地试探匹配,当匹配不成功的话,我们就应该回朔,尝试再用*
多匹配
一位继续尝试看是否能够成功,这个reset的过程我们对两个Pointer都要reset
- 假如我们上一次已经尝试用
*
匹配了n个字符,那么s
的pointer应该设置到上一次匹配n个字符的后一位 - 而
p
的pointer呢,我们应该还是从*
后面开始新一次的尝试
所以我们要有两个变量
star
记录*
出现的位置lastMatch
记录上一次对s
匹配到的位置
而根据这个文章分析,我们只需要回去尝试最后一个*
就可以。
Solution
DP
超时
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
if len(p) == 0:
return len(s) == 0
lengthS = len(s)
lengthP = len(p)
dp = [[False for i in range(lengthP + 1)] for j in range(lengthS + 1)]
dp[0][0] = True
# init state, match no characters
# last char in pattern has to be "*", which match 0 characters
for i in range(1, lengthP + 1):
if p[i-1] == "*":
dp[0][i] = True
else:
break
for i in range(1, lengthS + 1):
for j in range(1, lengthP + 1):
if p[j-1] != "?" and p[j-1] != "*":
if dp[i-1][j-1] and s[i-1] == p[j-1]:
dp[i][j] = True
elif p[j-1] == "?":
dp[i][j] = dp[i-1][j-1]
else: # "*" can't be first char
if dp[i][j-1]:
# match 0
dp[i][j] = True
elif dp[i-1][j-1]:
# match 1
dp[i][j] = True
elif dp[i-1][j]:
# match 2+, 往前退回
dp[i][j] = True
return dp[lengthS][lengthP]
backtracking + dfs
def isMatch(self, s, p):
# write your code here
if len(p) == 0: return len(s) == 0
if p[0] != "*":
if len(s) == 0 or (s[0] != p[0] and p[0] != "?"):
return False
return self.isMatch(s[1:], p[1:])
else:
for i in range(0, len(s)+1):
if self.isMatch(s[i:], p[1:]):
return True
return False
Two-pointer 做法
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
pI = 0
sI = 0
lastMatch = -1
star = -1
while sI < len(s):
if pI < len(p) and (p[pI] == "?" or p[pI] == s[sI]):
# 当是"?"或者是匹配字符时,不要考虑别的,直接都往后一位
pI += 1
sI += 1
elif pI < len(p) and p[pI] == "*":
# 当是 * 的时候, 就应该从匹配0个开始尝试
# start 记录 * 的位置以便下次reset
# lastMatch 设为当前匹配到的s的位置
# 只前进p的指针,表示先尝试对s匹配0个
star = pI
lastMatch = sI
pI += 1
elif star != -1:
# 前面都没有满足或者j已经超出范围了,无法匹配了,就应该重设了
# p的指针重设到*的后面
# s的指针重设到上一次尝试匹配n个字符的后一个
pI = star + 1
lastMatch += 1
sI = lastMatch
else:
# 没有*,已经无法匹配,直接返回 False
return False
# 如果p的指针还没有到底的话,只能是将*的跳过
while pI < len(p) and p[pI] == "*":
pI += 1
# 如果p的指针后面还有多余的非*的字符,说明无法匹配
# 如果到底了,说明成功匹配
return pI == len(p)