题目:
题目链接: https://leetcode-cn.com/problems/regular-expression-matching/
解题思路:
方法一:回溯
因为是要求对整个字符串匹配,不是通常理解的任意位置匹配,所以从s和p的开头开始匹配
p开头的字符有这么几种情况:
- '.',表示任意单个字符
- 任意a-z的小写字母,此时根据下一个字符,需要区分两种情况处理
- '*',表示匹配任意字符
- 任意a-z的小写字母,表示当前字符必须匹配
根据上述情况,匹配时的大致流程如下:
- 查看p的第一个字符,是否为'.'或者s的第一个字符
- 如果p的第二个字符是'*',则进行下记两次递归调用
- 如果p的第一个字符,与s的第一个字符匹配,则递归调用时,继续p的值不变,s的值从第二个字符开始,目的是为了匹配多个首字符的情况出现,即调用时的参数为(s[1:], p)
- 如果第一个字符不匹配,则递归调用时,s的值不变,p从第三个字符开始,目的是为了消除'*'的匹配,继续后面的匹配,即调用时的参数为(s, p[2:])
- 其他情况,如果首字符不匹配,则直接返回False,如果首字符匹配,跳过s和p的首字符,递归调用自己,即调用时的参数为(s[1:], p[1:])
过程中匹配的图示如下:
假设匹配时,s = 'aab', p = 'c*a*b*',匹配流程如下:
a a b c * a * b 首字符不匹配,p的第二个字符为*,s不变,更新p = p[2:] = 'a*b',再次递归:
a a b a * b 首字符匹配,p的第二个字符为*,p不变,更新s = s[1:] = 'ab',再次递归:
a b a * b 首字符匹配,p的第二个字符为*,p不变,更新s = s[1:] = 'b',再次递归:
b a * b 首字符不匹配,p的第二个字符为*,s不变,更新p = p[2:] = 'b':
b b 首字符匹配,并且s和p后续都没有字符了,返回True
方法二:回溯 + DP
匹配方法基本与方法一相同,不同的地方为,添加变量保存遍历过的结果,减少递归调用,提升效率
代码实现:
方法一:
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if not p:
return not s
first_match = bool(s and p[0] in ['.', s[0]])
if len(p) >= 2 and p[1] == '*':
return self.isMatch(s, p[2:]) or (first_match and self.isMatch(s[1:], p))
else:
return first_match and self.isMatch(s[1:], p[1:])
方法二:
class Solution(object):
def isMatch(self, text, pattern):
memo = {}
def dp(i, j):
if (i, j) not in memo:
if j == len(pattern):
ans = i == len(text)
else:
first_match = i < len(text) and pattern[j] in {text[i], '.'}
if j+1 < len(pattern) and pattern[j+1] == '*':
ans = dp(i, j+2) or first_match and dp(i+1, j)
else:
ans = first_match and dp(i+1, j+1)
memo[i, j] = ans
return memo[i, j]
return dp(0, 0)
作者:LeetCode
链接:https://leetcode-cn.com/problems/regular-expression-matching/solution/zheng-ze-biao-da-shi-pi-pei-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。