题目描述:
思路一:递归
递归的终止条件:
(1)如果s字符串的长度为0,如果此时字符串p当且仅当有形如"a* b* c* d* e*"这样的格式时,返回true;否则,返回false。
(2)如果s字符串的长度不为0,而p字符串的长度为0,返回false。
递归的过程:
(1)如果s的最后一个字符与p的最后一个字符相等,或者说p的最后一个字符为".",那么我们直接看字符串s中除去最后一个字符的字符串能否与字符串p中除去最后一个字符的字符串相匹配。
(2)如果p的最后一个字符为"*",这种情况比较复杂,又分为两种情况。
a.如果s的最后一个字符既不与p的最后第二个字符相等,p的最后第二个字符也不为".",那么我们直接看字符串s中除去最后一个字符的字符串能否与字符串p中除去最后两个字符的字符串相匹配。
b.如果s的最后一个字符与p的最后第二个字符相等,或者说p的最后第二个字符为".",,这种情况比较复杂,又分为三种情况。
b-1:我们看字符串s中除去最后一个字符的字符串能否与字符串p相匹配(即把s中的最后一个字符与p的最后一个字符(*)相匹配)。
b-2:我们看字符串s能否与字符串p中除去最后一个字符的字符串相匹配(即把s中的最后一个字符与p的最后第二个字符相匹配)。
b-3:我们看字符串s中除去最后一个字符的字符串能否与字符串p中除去最后两个字符的字符串相匹配(直接舍去p中的最后两个字符)。
只要上述b-1、b-2、b-3三种情况中有一种情况相匹配,我们就返回true。如果三种情况都不匹配,我们就返回false。
每一次递归的时间复杂度是O(1)级别的,我们最多需要递归m * n次,其中m为字符串s的长度,n为字符串p的长度,时间复杂度是O(m * n)。由于递归存在对系统栈的调用,因此空间复杂度与递归深度成正比,而递归的最大深度是m * n,因此空间复杂度是O(m * n)。
python解法
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m= len(s)
n= len(p)
if (m!= 0 and n== 0):
return False
if m== 0:
if n%2==1:
return False
i= 1
while (i< n and p[i]=='*'):
i= i+2
if i== n+1:
return True
else:
return False
if s[m-1]==p[n-1] or p[n-1]=='.':
return self.isMatch(s[0:m-1],p[0:n-1])
if p[n-1]=='*':
if s[m-1]!= p[n-2] and p[n-2]!='.':
return self.isMatch(s,p[0:n-2])
else:
return self.isMatch(s,p[0:n-1]) or self.isMatch(s,p[0:n-2]) or self.isMatch(s[0:m-1],p)
return False
思路二:动态规划
用题给的示例4来模拟递归的过程如下图所示
图中紫色椭圆所在区域就是递归过程中出现的重叠子问题,既然发现了重叠子问题,那么肯定就可以用动态规划来解决!而动态规划的关键是状态定义的合适选取以及发现正确的状态转移。
状态定义:f(x, y)------字符串s中[0, x - 1]范围内的字符串能否匹配字符串p中[0, y - 1]范围内的字符串
状态转移:
(1)如果p(y) == ‘.’, f(x, y) = f(x - 1, y - 1)。
(2)如果p(y) == s(x), f(x, y) = f(x - 1, y - 1)。
(3)如果p(y) == '’,
a.如果s(x) == p(y - 1) || p(y - 1) == ‘.’,
a-1:使用’‘号进行匹配——f(x - 1, y)
a-2:只使用’‘号前面的那个字符匹配,不使用’‘匹配——f(x, y - 1)
a-3:’*'号前面的那个字符在匹配的过程当中一个都不使用——f(x, y - 2)
f(x, y) = f(x - 1, y) || f(x, y - 1) || f(x, y - 2)。
b.如果s(x) != p(y - 1) && p(y - 1) != ‘.’
*号前面的那个字符在匹配的过程当中一个都不使用,f(x, y) = f(x, y - 2)。
为了处理s为空的情形,我们定义状态转移数组matched的行数和列数分别为s.length() + 1和p.length() + 1。显然我们有matched[0][0] = true。对于第0行,相当于字符串s为空,就是思路一中递归的终止条件(1)中的情形。
此思路的时间复杂度是O(m * n),其中m为字符串s的长度,n为字符串p的长度,但相比思路一省略了很多重叠子问题的重复计算。空间复杂度是一个boolean类型的m * n的数组,因此空间复杂度是O(m * n)。
python解法
class Solution:
def isMatch(self, s: str, p: str) -> bool:
#if not s or not p:
#return False
s_len = len(s)
p_len = len(p)
dp = [[False] * (p_len + 1) for _ in range(s_len + 1)]
print(dp)
dp[0][0] = True
for i in range(p_len):
if p[i] == "*" and dp[0][i - 1]:
dp[0][i + 1] = True
#print(dp)
for i in range(s_len):
for j in range(p_len):
if p[j] == s[i] or p[j] == ".":
dp[i + 1][j + 1] = dp[i][j]
elif p[j] == "*":
if p[j - 1] != s[i]:
dp[i + 1][j + 1] = dp[i + 1][j - 1]
if p[j-1] == s[i] or p[j-1] == ".":
dp[i+1][j+1] = (dp[i][j+1] or dp[i+1][j] or dp[i+1][j-1])
#print(dp)
return dp[-1][-1]