LeetCode-10-正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
1 | '.' 匹配任意单个字符 |
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
1 | 输入: |
示例 2:
1 | 输入: |
示例 3:
1 | 输入: |
示例 4:
1 | 输入: |
示例 5:
1 | 输入: |
思路:
可以使用动态规划来解此题。
首先定义状态,有过求LCS和LIC的经验,我们很轻易类似的写出该题的状态定义:
1 | dp[i][j] 串S以i结尾,串P以j结尾是否能够匹配。 |
我们考虑状态转移方程:
先分类考虑:
s[i] != p[j] && p[j] != ‘.’ && p[j] != ‘*’
s[i] == p[j]
- p[j] == ‘.’
- p[j] == ‘*’
第一种情况显然是false。
第二种情况是说明可以匹配,所以由S前i-1,P前j-1匹配的情况决定。
第三种情况把’.’看做s[i]可以和第二种情况合并
重点是第四种情况,p[j]为’*’ 的情况:
单独一个‘ ’是不构成语义的,所以出现‘ ’就要看前一个字符,而前面有可能出现的又有‘.’和字母两种情况。
前面说过了,我们遇见‘.’直接把他当作与s[i]相等的字符即可。不需要做特殊处理。
所以就只剩下了‘*’ 前面是字母的
而分成的两种情况:
- ‘*’前面的字母和s[i-1]不匹配。
- ‘*’前面的字母和s[i-1]匹配。
第一种情况由于’*’可以代表零个之前的字符。例如:
1 | aabc |
是可以匹配的。
所以我们遇到’*’前面的字母和s[i-1]不匹配就可以跳过这两个字符。即
1 | dp[i][j] = dp[i][j-2] |
最后’*’前面的字母和s[i-1]匹配:
那么就有按照‘*’的语义,又需要划分三种情况:
- *加上前面的字符不与s[i-1]匹配。
- 加上前面的字符只与s[i-1]匹配 即 作废。
- *加上前面的字符可以与多个s[i-1]匹配。
前两种情况其实与我们之前分析的不加‘*’的情况基本一致。
那么与多个字符匹配怎么转移呢?
我们确定匹配多个字符可以一个一个来,只要dp[i-1][j]可以匹配。那么只要[j]是,则dp[i][j]一定可以匹配上。(别忘了,我们的前提条件是 和之前的字母匹配)
1 |
|
至此我们就将所有情况分析完毕。
代码:
1 | class Solution { |
这里有一个点必须初始化,因为下标是从1开始的,无法访问到0,当遇到处理 aa 和c c c* aa 匹配的情况时,是需要访问到0的位置的,所以需要预处理。前缀可以为空的情况。