Skip to content

Commit 3471e18

Browse files
committed
feat: add python and java solutions to lcof question
添加《剑指 Offer》题解:面试题19. 正则表达式匹配
1 parent 4a36977 commit 3471e18

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
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+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class Solution {
2+
public boolean isMatch(String s, String p) {
3+
int m = s.length() + 1, n = p.length() + 1;
4+
if (n == 1) {
5+
return m == 1;
6+
}
7+
boolean[][] dp = new boolean[m + 1][n + 1];
8+
dp[0][0] = true;
9+
dp[0][1] = false;
10+
for (int j = 1; j < n; ++j) {
11+
if (p.charAt(j - 1) == '*') {
12+
dp[0][j] = dp[0][j - 2];
13+
}
14+
}
15+
for (int i = 1; i < m; ++i) {
16+
for (int j = 1; j < n; ++j) {
17+
if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') {
18+
dp[i][j] = dp[i - 1][j - 1];
19+
} else if (p.charAt(j - 1) == '*') {
20+
if (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') {
21+
dp[i][j] = dp[i][j - 2] || dp[i - 1][j];
22+
} else {
23+
dp[i][j] = dp[i][j - 2];
24+
}
25+
} else {
26+
dp[i][j] = false;
27+
}
28+
}
29+
}
30+
return dp[m - 1][n - 1];
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
class Solution:
2+
def isMatch(self, s: str, p: str) -> bool:
3+
m, n = len(s) + 1, len(p) + 1
4+
if n == 1:
5+
return m == 1
6+
dp = [[False for _ in range(n)] for _ in range(m)]
7+
dp[0][0], dp[0][1] = True, False
8+
for j in range(2, n):
9+
if p[j - 1] == '*':
10+
dp[0][j] = dp[0][j - 2]
11+
for i in range(1, m):
12+
for j in range(1, n):
13+
if s[i - 1] == p[j - 1] or p[j - 1] == '.':
14+
dp[i][j] = dp[i - 1][j - 1]
15+
elif p[j - 1] == '*':
16+
if p[j - 2] == '.' or p[j - 2] == s[i - 1]:
17+
dp[i][j] = dp[i][j - 2] or dp[i - 1][j]
18+
else:
19+
dp[i][j] = dp[i][j - 2]
20+
else:
21+
dp[i][j] = False
22+
return dp[m - 1][n - 1]

0 commit comments

Comments
 (0)