[10][困难][动态规划] 正则表达式匹配
题目描述
10. 正则表达式匹配 剑指 Offer 19. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。 p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 示例 1:
示例 2:
示例 3:
示例 4:
示例 5:
解题思路
动态规划
状态的定义比较直观, dp[i][j]
表示字符串s
的前i
个字符能否与模式串p
的前j
个字符匹配.
状态转移方程有些麻烦. 可以看出*
字符是特殊的字符, 需要以p[j] == '*'
与否, 分别讨论.
p[j]不为*
如果p[j] == '.'
, 那么可以与任何一个字符匹配, 因此有dp[i][j] = dp[i - 1][j - 1]
.
如果p[j]
为任一字母, 需要判断p[j]
, s[i]
是否相等, 如果相等, 则dp[i][j] = dp[i - 1][j - 1]
; 如果不相等, 则dp[i][j] = False
.
p[k]为*
由于*
代表的是匹配0次或任意多次, 因此, 分为两种情况讨论, 只要满足其中的任何一种情况, 即为True
.
匹配0次的情况, 即跳过当前的*
字符, 以及前面紧邻的.
或字母字符. 则有dp[i][j] = dp[i][j - 2]
匹配1~n次的情况, 需要判断p[j-1]
与s[i], s[i-1], ...
的字符是否相等, 一直找到不相等的字符为止, 例如s[i-a]
与p[j-1]
不相等, 则dp[i][j] = dp[i-a][j-2]
.
但其实我们只需要比较p[j-1]
与s[i]
是否相等, 因此我们是从左到右搜索, 这样p[j-1]
与s[i]
之前的字符是否相等, 已经包含在dp[i-1][j]
中, 而无需向前继续寻找.
因此我们有, 如果p[j-1]
与s[i]
相等, 则dp[i][j] = dp[i - 1][j]
, 否则为False
.
因此p[k]
为*
的情况下, dp[i][j] = dp[i][j - 2] or (s[i] == p[j - 1] and dp[i - 1][j])
状态转移方程考虑完毕.
最后考虑下初始状态. 要考虑空字符串和模式串的情况, 因此如果字符串和匹配串的长度分别为n
和m
, 那么我们状态矩阵的大小应为(n + 1, m + 1)
, 各个维度的索引0
代表空字符串.
则dp[0][0] = True
, 空字符串肯定是匹配的. dp[i][0]
肯定是False
, 因为任何非空字符串肯定与空模式串不匹配. dp[0][j]
是要注意的情况, 我们对于非*
位置肯定是False
, 而*
位置, 只能考虑不匹配任何字符的情况, 因此有dp[0][j] = dp[0][j - 2]
. 这样其实遇到第一个连续的非*
字符, 至此开始, 后续都是False.
整体代码如下:
最后更新于