|
| 1 | +# [面试题19. 正则表达式匹配](https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof/) |
| 2 | + |
| 3 | +## 题目描述 |
| 4 | +请实现一个函数用来匹配包含`'. '`和`'*'`的正则表达式。模式中的字符`'.'`表示任意一个字符,而`'*'`表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串`"aaa"`与模式`"a.a"`和`"ab*ac*a"`匹配,但与`"aa.a"`和`"ab*a"`均不匹配。 |
| 5 | + |
| 6 | +**示例 1:** |
| 7 | + |
| 8 | +``` |
| 9 | +输入: |
| 10 | +s = "aa" |
| 11 | +p = "a" |
| 12 | +输出: false |
| 13 | +解释: "a" 无法匹配 "aa" 整个字符串。 |
| 14 | +``` |
| 15 | + |
| 16 | +**示例 2:** |
| 17 | + |
| 18 | +``` |
| 19 | +输入: |
| 20 | +s = "aa" |
| 21 | +p = "a*" |
| 22 | +输出: true |
| 23 | +解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。 |
| 24 | +``` |
| 25 | + |
| 26 | +**示例 3:** |
| 27 | + |
| 28 | +``` |
| 29 | +输入: |
| 30 | +s = "ab" |
| 31 | +p = ".*" |
| 32 | +输出: true |
| 33 | +解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。 |
| 34 | +``` |
| 35 | + |
| 36 | +**示例 4:** |
| 37 | + |
| 38 | +``` |
| 39 | +输入: |
| 40 | +s = "aab" |
| 41 | +p = "c*a*b" |
| 42 | +输出: true |
| 43 | +解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。 |
| 44 | +``` |
| 45 | + |
| 46 | +**示例 5:** |
| 47 | + |
| 48 | +``` |
| 49 | +输入: |
| 50 | +s = "mississippi" |
| 51 | +p = "mis*is*p*." |
| 52 | +输出: false |
| 53 | +``` |
| 54 | + |
| 55 | +- `s` 可能为空,且只包含从 `a-z` 的小写字母。 |
| 56 | +- `p` 可能为空,且只包含从 `a-z` 的小写字母,以及字符 `.` 和 `*`。 |
| 57 | + |
| 58 | + |
| 59 | +## 解法 |
| 60 | +动态规划法,`dp[i][j]` 表示 s 的前 i 项和 p 的前 j 项是否匹配。 |
| 61 | + |
| 62 | +现在如果已知了 `dp[i-1][j-1]` 的状态,我们该如何确定 `dp[i][j]` 的状态呢?我们可以分三种情况讨论,其中,前两种情况考虑了所有能匹配的情况,剩下的就是不能匹配的情况了: |
| 63 | + |
| 64 | +1. `s[i] == p[j]` or `p[j] == '.'`:比如 ab**b** 和 ab**b**,或者 ab**b** 和 ab**\.** ,很容易得到 `dp[i][j]` = `dp[i-1][j-1]` = True。因为 ab 和 ab 是匹配的,如果后面分别加一个 b,或者 s 加一个 b 而 p 加一个 `.` ,仍然是匹配的。 |
| 65 | + |
| 66 | +2. `p[j] == '*'`:当 `p[j] == '*'` 时,由于 `*` 与前面的字符相关,因此我们比较 `*` 前面的字符 `p[j-1]` 和 `s[i]` 的关系。根据 `*` 前面的字符与 s[i] 是否相等,又可分为以下两种情况: |
| 67 | + |
| 68 | +- `p[j-1] != s[i]`:如果 `*` 前一个字符匹配不上,`*` 匹配了 0 次,应忽略这两个字符,看 `p[j-2]` 和 `s[i]` 是否匹配。 这时 `dp[i][j] = dp[i][j-2]`。 |
| 69 | + |
| 70 | +- `p[j-1] == s[i]` or `p[j-1] == '.'`:`*` 前面的字符可以与 s[i] 匹配,这种情况下,`*` 可能匹配了前面的字符的 0 个,也可能匹配了前面字符的多个,当匹配 0 个时,如 `ab` 和 `abb*`,或者 `ab` 和 `ab.*` ,这时我们需要去掉 p 中的 `b*` 或 `.*` 后进行比较,即 `dp[i][j] = dp[i][j-2]`;当匹配多个时,如 `abbb` 和 `ab*`,或者 `abbb` 和 `a.*`,我们需要将 s[i] 前面的与 p 重新比较,即 `dp[i][j] = dp[i-1][j]`。 |
| 71 | + |
| 72 | +3. 其他情况:以上两种情况把能匹配的都考虑全面了,所以其他情况为不匹配,即 `dp[i][j] = False` |
| 73 | + |
| 74 | +注:递归法超时。 |
| 75 | + |
| 76 | +### Python3 |
| 77 | +```python |
| 78 | +class Solution: |
| 79 | + def isMatch(self, s: str, p: str) -> bool: |
| 80 | + m, n = len(s) + 1, len(p) + 1 |
| 81 | + if n == 1: |
| 82 | + return m == 1 |
| 83 | + dp = [[False for _ in range(n)] for _ in range(m)] |
| 84 | + dp[0][0], dp[0][1] = True, False |
| 85 | + for j in range(2, n): |
| 86 | + if p[j - 1] == '*': |
| 87 | + dp[0][j] = dp[0][j - 2] |
| 88 | + for i in range(1, m): |
| 89 | + for j in range(1, n): |
| 90 | + if s[i - 1] == p[j - 1] or p[j - 1] == '.': |
| 91 | + dp[i][j] = dp[i - 1][j - 1] |
| 92 | + elif p[j - 1] == '*': |
| 93 | + if p[j - 2] == '.' or p[j - 2] == s[i - 1]: |
| 94 | + dp[i][j] = dp[i][j - 2] or dp[i - 1][j] |
| 95 | + else: |
| 96 | + dp[i][j] = dp[i][j - 2] |
| 97 | + else: |
| 98 | + dp[i][j] = False |
| 99 | + return dp[m - 1][n - 1] |
| 100 | + |
| 101 | +``` |
| 102 | + |
| 103 | +### Java |
| 104 | +```java |
| 105 | +class Solution { |
| 106 | + public boolean isMatch(String s, String p) { |
| 107 | + int m = s.length() + 1, n = p.length() + 1; |
| 108 | + if (n == 1) { |
| 109 | + return m == 1; |
| 110 | + } |
| 111 | + boolean[][] dp = new boolean[m + 1][n + 1]; |
| 112 | + dp[0][0] = true; |
| 113 | + dp[0][1] = false; |
| 114 | + for (int j = 1; j < n; ++j) { |
| 115 | + if (p.charAt(j - 1) == '*') { |
| 116 | + dp[0][j] = dp[0][j - 2]; |
| 117 | + } |
| 118 | + } |
| 119 | + for (int i = 1; i < m; ++i) { |
| 120 | + for (int j = 1; j < n; ++j) { |
| 121 | + if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') { |
| 122 | + dp[i][j] = dp[i - 1][j - 1]; |
| 123 | + } else if (p.charAt(j - 1) == '*') { |
| 124 | + if (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') { |
| 125 | + dp[i][j] = dp[i][j - 2] || dp[i - 1][j]; |
| 126 | + } else { |
| 127 | + dp[i][j] = dp[i][j - 2]; |
| 128 | + } |
| 129 | + } else { |
| 130 | + dp[i][j] = false; |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + return dp[m - 1][n - 1]; |
| 135 | + } |
| 136 | +} |
| 137 | +``` |
| 138 | + |
| 139 | +### ... |
| 140 | +``` |
| 141 | +
|
| 142 | +``` |
0 commit comments