题目描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"
与模式"a.a"
和"ab*ac*a"
匹配,但是与"aa.a"
和"ab*a"
均不匹配
分析
分析递归
。
每次从字符串里取出一个字符与模式中的字符匹配,如果模式中的字符是‘.’
,它可以匹配字符串中的任意字符
,如果不是,那么如果它与字符串中的字符相等则匹配。当字符串的字符和模式的字符匹配时,接着匹配后面的字符。总的分为两种情况。- 接下来考虑如果模式串存在第二个字符并且第二个字符是
"*"
:- 如果模式中的第一个字符和字符串中的第一个字符不匹配(两种情况,
不等
或者字符串为None
),则在模式上后移两个字符,相当于忽略‘’和它前面的字符,因为‘’可以匹配字符串中的0个字符; - 如果模式中的第一个字符和字符串中的第一个字符匹配,则字符串后移一个字符,而在模式上又有两种选择:
1. 只模式串上后移两个字符。(例如字符串"ab"
和模式"a*ab"
)
2. 模式保持不变,字符串后移一个字符。(例如字符串"aabbba"
和模式"aab*a"
)
- 如果模式中的第一个字符和字符串中的第一个字符不匹配(两种情况,
- 考虑模式中的第二个字符不是‘*’:
- 如果字符串中的第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的字符串和模式;
- 如果字符串中的第一个字符和模式中的第一个字符不匹配,则直接返回
false
。
- 接下来考虑如果模式串存在第二个字符并且第二个字符是
代码
# -*- coding:utf-8 -*-
class Solution:
# s, pattern都是字符串
def match(self, s, pattern):
# write code here
if not s and not pattern:
return True
if s and not pattern:
return False
if not s and pattern:
if len(pattern)>=2 and pattern[1] == '*':
return self.match(s, pattern[2:])
else:
return False
if s and pattern:
if len(pattern)>=2 and pattern[1] == '*':
if s[0] == pattern[0] or pattern[0] == '.':
return self.match(s[1:], pattern) or self.match(s, pattern[2:])
else:
return self.match(s, pattern[2:])
else:
if pattern[0]==s[0] or pattern[0] == '.':
return self.match(s[1:], pattern[1:])
else:
return False
class Solution:
def isMatch1(self, s: str, p: str) -> bool:
'''
dp[i][j] 代表s[:i] p[:j]是否匹配
dp[i][j] = dp[i-1][j-1] if s[i] == p[j] or p[j] == '.' match
= dp[i][j-2] 不匹配 p[j] == '*'
= dp[i-1][j-2] 匹配一个字符 s[i]=p[j−1] p[j] == '*'
= dp[i-2][j-2] 匹配两个字符 s[i−1]=s[i]=p[j−1] p[j] == '*'
...
核心重点:字母 * 星号的组合在匹配的过程中,本质上只会有两种情况:
1. 匹配 s 末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配;
2. 不匹配字符,将该组合扔掉,不再进行匹配。
dp[i][j] = dp[i-1][j-1] if s[i] == p[j] or p[j] == '.' 令为 match(i, j)
= dp[i-1][j] or dp[i][j-2] if p[j] == '*' and match(i, j-1)
= dp[i][j-2] if p[j] == '*' and not match(i, j-1)
边界: dp[0][0] True
dp[i][0] False
dp[0][j] 分情况讨论了, 连续偶数个 * True p = 'a*.*'
res = dp[-1][-1]
m = len(s)
n = len(p)
时间复杂度 O(mn)
空间复杂度 O(mn)
'''
def match(i, j):
'''
:param i: s 的索引
:param j: p 的索引
:return: 是否单个匹配
'''
if j<0 :
return False
if s[i]==p[j] or p[j]=='.':
return True
else:
return False
m, n = len(s), len(p)
dp = [[False]*(n+1) for _ in range(m+1)]
# 限定边界
dp[0][0] = True
for j in range(1, n, 2):
if p[j] == '*':
dp[0][j+1] = True
else:
break
# 状态转移
for i in range(1, m+1):
for j in range(1, n+1):
if p[j-1] == '*':
if match(i-1, j-2):
dp[i][j] = dp[i-1][j] or dp[i][j-2]
else:
dp[i][j] = dp[i][j-2]
else:
if match(i-1, j-1):
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = False # 初始化一致
return dp[-1][-1]
def isMatch(self, s, p):
'''
dp[i][j] 代表s[:i] p[:j]是否匹配
dp[i][j] = dp[i-1][j-1] if s[i] == p[j] or p[j] == '.' match
= dp[i][j-2] 不匹配 p[j] == '*'
= dp[i-1][j-2] 匹配一个字符 s[i]=p[j−1] p[j] == '*'
= dp[i-2][j-2] 匹配两个字符 s[i−1]=s[i]=p[j−1] p[j] == '*'
...
核心重点:字母 * 星号的组合在匹配的过程中,本质上只会有两种情况:
1. 匹配 s 末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配;
2. 不匹配字符,将该组合扔掉,不再进行匹配。
dp[i][j] = dp[i-1][j-1] if s[i] == p[j] or p[j] == '.' 令为 match(i, j)
= dp[i-1][j] or dp[i][j-2] if p[j] == '*' and match(i, j-1)
= dp[i][j-2] if p[j] == '*' and not match(i, j-1)
边界: dp[0][0] True
dp[i][0] False
dp[0][j] 分情况讨论了, 连续偶数个 * True p = 'a*.*'
res = dp[-1][-1]
m = len(s)
n = len(p)
时间复杂度 O(mn)
空间复杂度 O(n)
空间优化
'''
def match(i, j):
'''
:param i: s 的索引
:param j: p 的索引
:return: 是否单个匹配
'''
if j<0 :
return False
if s[i]==p[j] or p[j]=='.':
return True
else:
return False
m, n = len(s), len(p)
dp = [False]*(n+1)
# 限定边界
dp[0] = True
for j in range(1, n, 2):
if p[j] == '*':
dp[j+1] = True
else:
break
# 状态转移
for i in range(1, m+1):
last = True if i==1 else False
dp[0] = False
for j in range(1, n+1):
temp = dp[j]
if p[j-1] == '*':
if match(i-1, j-2):
dp[j] = dp[j] or dp[j-2]
else:
dp[j] = dp[j-2]
else:
if match(i-1, j-1):
dp[j] = last
else:
dp[j] = False
last = temp
return dp[-1]