Poison

10. Regular Expression Matching

DP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public boolean isMatch(String s, String p) {
// 定义 dp[i][j] 为 s 的前 i 个字符与 p 的前 j 个字符是否匹配
boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];

// 空字符串与空模式匹配
dp[0][0] = true;

// if p.charAt(j - 1) is alpha, then dp[i][j] = s.charAt(i - 1) == p.charAt(j - 1) && dp[i - 1][j - 1]
// if p.charAt(j - 1) is '.', then dp[i][j] = dp[i - 1][j - 1]
// if p.chatAt(j - 1) is '*', then can match zero times, multiple times

// 因为空字符串可能匹配多种正则表达式,所以需要 i 从 0 开始计算,如模式 'a*', 'a*b*', 'a*b*c*'
for (int i = 0; i <= s.length(); i++) {
// 因为空正则表达式不匹配除空字符串之外的字符串,所以 j 从 1 开始
for (int j = 1; j <= p.length(); j++) {
char c = p.charAt(j - 1);
if (c == '.') {
if (i - 1 >= 0) {
dp[i][j] |= dp[i - 1][j - 1];
}
} else if (c == '*') {
// match zero times
if (j - 2 >= 0) {
dp[i][j] |= dp[i][j - 2]; // 注意此处是 j - 2, '*' 及前一个字符都需要消除
}
// match multiple times
if (i - 1 >= 0 && j - 2 >= 0) {
dp[i][j] |= (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') && dp[i - 1][j];
}
} else {
// c is alpha
if (i - 1 >= 0) {
dp[i][j] |= s.charAt(i - 1) == c && dp[i - 1][j - 1];
}
}
}
}

return dp[s.length()][p.length()];
}
}

注意处理初始状态,索引越界问题,状态变更使用 |=

DP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
public boolean isMatch(String s, String p) {
// 定义 dp[i][j] 为 s 前 i 个字符与 p 前 j 个字符是否匹配
boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];

// 当 p 为空时,仅当 s 为空才能匹配
dp[0][0] = true;
// 当 s 为空时,可能与 'a*', 'a*a*' 等字符串匹配
for (int j = 1; j <= p.length(); j++) {
char pChar = p.charAt(j - 1);
if (j - 2 >= 0 && pChar == '*') {
dp[0][j] = dp[0][j - 2];
}
}

for (int i = 1; i <= s.length(); i++) {
for (int j = 1; j <= p.length(); j++) {
char sChar = s.charAt(i - 1);
char pChar = p.charAt(j - 1);
if (pChar == '.') {
dp[i][j] = dp[i - 1][j - 1];
} else if (pChar == '*') {
// * 匹配零次时
if (j - 2 >= 0) {
dp[i][j] = dp[i][j - 2];
}
// * 匹配一次时
if (!dp[i][j] && j - 2 >= 0) {
char c = p.charAt(j - 2);
dp[i][j] = (c == sChar || c == '.') && dp[i - 1][j - 2];
}
// * 匹配多次时
if (!dp[i][j] && j - 2 >= 0) {
char c = p.charAt(j - 2);
dp[i][j] = (c == sChar || c == '.') && dp[i - 1][j];
}
} else {
// pc is alpha
dp[i][j] = dp[i - 1][j - 1] && sChar == pChar;
}
}
}

return dp[s.length()][p.length()];
}
}
Reference

10. Regular Expression Matching
剑指 Offer 19. 正则表达式匹配
逐行详细讲解,由浅入深,dp和递归两种思路