mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-31 11:05:36 +00:00
Update 19. 正则表达式匹配.md
补充动态规划解法说明及状态转移配图,调整代码实现并精简 '*' 匹配的处理逻辑,补充复杂度分析。
This commit is contained in:
+28
-18
@@ -10,31 +10,41 @@
|
||||
|
||||
## 解题思路
|
||||
|
||||
应该注意到,'.' 是用来当做一个任意字符,而 '\*' 是用来重复前面的字符。这两个的作用不同,不能把 '.' 的作用和 '\*' 进行类比,从而把它当成重复前面字符一次。
|
||||
'\*' 不能单独看,它和前面的字符构成一个整体 "x\*",表示 x 出现 0 次或多次;'.' 只匹配一个任意字符,不会重复。
|
||||
|
||||
用动态规划求解。dp[i][j] 表示 s 的前 i 个字符能否匹配 p 的前 j 个字符,按 p 的第 j 个字符分情况:
|
||||
|
||||
- p[j-1] 是普通字符或 '.':它必须和 s[i-1] 匹配,并且前面的部分也要匹配,dp[i][j] = dp[i-1][j-1];
|
||||
- p[j-1] 是 '\*',记前一个字符为 x:让 "x\*" 匹配 0 次,相当于删掉这两个字符,dp[i][j] = dp[i][j-2];如果 x 能匹配 s[i-1](相等或 x 为 '.'),还可以让 "x\*" 吃掉 s[i-1],而 "x\*" 本身保留下来继续匹配前面的字符,dp[i][j] = dp[i-1][j]。两种情况有一种成立即可。
|
||||
|
||||
初始时 dp[0][0] = true;空串只能被 "a\*b\*" 这类每个字符都带 '\*' 的模式匹配,因此 p[j-1] 为 '\*' 时 dp[0][j] = dp[0][j-2]。
|
||||
|
||||
以 s = "abbc"、p = "c\*ab\*." 为例,dp 表和得到结果的一条路径如下:
|
||||
|
||||
<div align="center"> <img src="pics/offer19-regex-dp.png" width="640px"/> </div><br>
|
||||
|
||||
```java
|
||||
public boolean articleMatch(String s, String p) {
|
||||
|
||||
int m = s.length(), n = p.length();
|
||||
boolean[][] dp = new boolean[m + 1][n + 1];
|
||||
|
||||
dp[0][0] = true;
|
||||
for (int i = 1; i <= n; i++)
|
||||
if (p.charAt(i - 1) == '*')
|
||||
dp[0][i] = dp[0][i - 2];
|
||||
|
||||
for (int i = 1; i <= m; i++)
|
||||
for (int j = 1; j <= n; j++)
|
||||
if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.')
|
||||
for (int j = 2; j <= n; j++)
|
||||
if (p.charAt(j - 1) == '*')
|
||||
dp[0][j] = dp[0][j - 2];
|
||||
for (int i = 1; i <= m; i++) {
|
||||
for (int j = 1; j <= n; j++) {
|
||||
char sc = s.charAt(i - 1), pc = p.charAt(j - 1);
|
||||
if (pc == sc || pc == '.') {
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
else if (p.charAt(j - 1) == '*')
|
||||
if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.') {
|
||||
dp[i][j] |= dp[i][j - 1]; // a* counts as single a
|
||||
dp[i][j] |= dp[i - 1][j]; // a* counts as multiple a
|
||||
dp[i][j] |= dp[i][j - 2]; // a* counts as empty
|
||||
} else
|
||||
dp[i][j] = dp[i][j - 2]; // a* only counts as empty
|
||||
|
||||
} else if (pc == '*') {
|
||||
char x = p.charAt(j - 2);
|
||||
dp[i][j] = dp[i][j - 2] // x* 匹配 0 次
|
||||
|| ((x == sc || x == '.') && dp[i - 1][j]); // x* 再匹配一个 sc
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[m][n];
|
||||
}
|
||||
```
|
||||
|
||||
时间和空间复杂度都是 O(MN)。
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
Reference in New Issue
Block a user