10. 正则表达式匹配
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式匹配。
1 | '.' 匹配任意单个字符 |
所谓匹配,是要涵盖 整个 字符串 s
的,而不是部分字符串。
说明:
s
可能为空,且只包含从a-z
的小写字母。p
可能为空,且只包含从a-z
的小写字母,以及字符.
和*
。
示例 1:
1 | 输入: |
示例 2:
1 | 输入: |
示例 3:
1 | 输入: |
示例 4:
1 | 输入: |
示例 5:
1 | 输入: |
我们每次从字符串 p 中取出一个字符或者字符 + 星号的组合,并在 s 中进行匹配。对于 p 中的一个字符,它只能匹配 s 中的一个字符;对于字符和星号的组合,它可以在 s 中匹配任意个字符。因此,我们考虑使用动态规划,对匹配的方案进行枚举。
我们使用 f[i][j]
表示 s 的前 i 个字符与 p 中的前 j 个字符是否能够匹配。在进行状态转移时,我们考虑 p 的第 j 个字符的匹配情况:
- 如果 p 的第 j 个字符是一个小写字母,那么必须在 s 中匹配一个相同的小写字母即:
如果 s 的第 i 个字符与 p 的第 j 个字符不同则返回 false,如果它们相同,则匹配结果等于两个字符串前面部分匹配的结果
如果 p 的第 j 个字符是
*
,那么就表示我们可以对 p 的j-1
个字符匹配任意次。在匹配 0 次的情况下:f[i][j] = f[i][j-2]
(直接丢弃这个字母加星号的组合);在匹配 1 次的情况下:f[i][j] = f[i-1][j-2], if s[i] = p[j-1]
;在匹配 2 次的情况下:f[i][j] = f[i-2][j-2], if s[i-1] = s[i] = p[j-1]
;在匹配 3 次的情况下:f[i][j] = f[i-3][j-2], if s[i-2] = s[i-1] = s[i] = p[j-1]
……仔细思考,字母 + 星号只有两种情况:
- 匹配 s 末尾的一个字符,将该字符扔掉,该组合继续匹配
- 不匹配字符,将组合扔掉,不再进行匹配
f[i][j] = f[i-1][j], if s[i] = p[j-1]
代表扔掉 s 末尾的一个字符,继续匹配;f[i][j] = f[i][j-2], if s[i] = p[j-1]
代表扔掉组合,不再匹配。
最终的状态转移方程如下:
字符串的字符下标是从 0 开始的,在实现上面的状态转移方程时,需要注意状态中每一维下标与实际字符下标的对应关系。
1 | class Solution { |
时间复杂度 O(mn),空间复杂度O(mn)。