Skip to content

Commit 6443f5e

Browse files
左程云左程云
authored andcommitted
补充leetcode题目10有关斜率优化的解并注释说明
1 parent 23f7c7f commit 6443f5e

File tree

2 files changed

+104
-172
lines changed

2 files changed

+104
-172
lines changed

src/topinterviewquestions/Problem_0010_RegularExpressionMatching.java

Lines changed: 104 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22

33
public class Problem_0010_RegularExpressionMatching {
44

5-
public static boolean isMatch1(String s, String p) {
6-
if (s == null || p == null) {
7-
return false;
8-
}
9-
char[] str = s.toCharArray();
10-
char[] pattern = p.toCharArray();
11-
return isValid(str, pattern) && process(str, pattern, 0, 0);
12-
}
13-
145
public static boolean isValid(char[] str, char[] pattern) {
156
for (char cha : str) {
167
if (cha == '.' || cha == '*') {
@@ -25,15 +16,26 @@ public static boolean isValid(char[] str, char[] pattern) {
2516
return true;
2617
}
2718

19+
// 课堂现场写
20+
public static boolean isMatch1(String s, String p) {
21+
if (s == null || p == null) {
22+
return false;
23+
}
24+
char[] str = s.toCharArray();
25+
char[] pattern = p.toCharArray();
26+
return isValid(str, pattern) && process1(str, pattern, 0, 0);
27+
}
28+
29+
// 课堂现场写
2830
// str[si.....] 能否被 pattern[pi...] 变出来
2931
// 潜台词:pi位置,pattern[pi] != '*'
30-
public static boolean process(char[] str, char[] pattern, int si, int pi) {
32+
public static boolean process1(char[] str, char[] pattern, int si, int pi) {
3133
if (si == str.length) { // si越界了
3234
if (pi == pattern.length) {
3335
return true;
3436
}
3537
if (pi + 1 < pattern.length && pattern[pi + 1] == '*') {
36-
return process(str, pattern, si, pi + 2);
38+
return process1(str, pattern, si, pi + 2);
3739
}
3840
return false;
3941
}
@@ -43,25 +45,26 @@ public static boolean process(char[] str, char[] pattern, int si, int pi) {
4345
}
4446
// si 没越界 pi 没越界
4547
if (pi + 1 >= pattern.length || pattern[pi + 1] != '*') {
46-
return ((str[si] == pattern[pi]) || (pattern[pi] == '.')) && process(str, pattern, si + 1, pi + 1);
48+
return ((str[si] == pattern[pi]) || (pattern[pi] == '.')) && process1(str, pattern, si + 1, pi + 1);
4749
}
4850
// si 没越界 pi 没越界 pi+1 *
4951
if (pattern[pi] != '.' && str[si] != pattern[pi]) {
50-
return process(str, pattern, si, pi + 2);
52+
return process1(str, pattern, si, pi + 2);
5153
}
5254
// si 没越界 pi 没越界 pi+1 * [pi]可配[si]
53-
if (process(str, pattern, si, pi + 2)) {
55+
if (process1(str, pattern, si, pi + 2)) {
5456
return true;
5557
}
5658
while (si < str.length && (str[si] == pattern[pi] || pattern[pi] == '.')) {
57-
if (process(str, pattern, si + 1, pi + 2)) {
59+
if (process1(str, pattern, si + 1, pi + 2)) {
5860
return true;
5961
}
6062
si++;
6163
}
6264
return false;
6365
}
6466

67+
// 课堂现场写
6568
public static boolean isMatch2(String s, String p) {
6669
if (s == null || p == null) {
6770
return false;
@@ -80,6 +83,7 @@ public static boolean isMatch2(String s, String p) {
8083
return isValid(str, pattern) && process2(str, pattern, 0, 0, dp);
8184
}
8285

86+
// 课堂现场写
8387
// str[si.....] 能否被 pattern[pi...] 变出来
8488
// 潜台词:pi位置,pattern[pi] != '*'
8589
public static boolean process2(char[] str, char[] pattern, int si, int pi, int[][] dp) {
@@ -136,56 +140,102 @@ public static boolean process2(char[] str, char[] pattern, int si, int pi, int[]
136140
return false;
137141
}
138142

139-
public static boolean isMatch3(String str, String exp) {
140-
if (str == null || exp == null) {
143+
// 以下的代码是课后的优化
144+
// 有代码逻辑精简的优化,还包含一个重要的斜率优化,请先理解课上的内容
145+
public static boolean isMatch3(String s, String p) {
146+
if (s == null || p == null) {
147+
return false;
148+
}
149+
char[] str = s.toCharArray();
150+
char[] pattern = p.toCharArray();
151+
return isValid(str, pattern) && process3(str, pattern, 0, 0);
152+
}
153+
154+
// 举例说明斜率优化:
155+
// 求状态(si = 3, pi = 7)时,假设状况如下
156+
// str : a a a b ...
157+
// si : 3 4 5 6 ...
158+
// pat : a * ? ...
159+
// pi : 7 8 9 ...
160+
// 状态(si = 3, pi = 7)的底层会依赖:
161+
// 状态(si = 3, pi = 9)
162+
// 状态(si = 4, pi = 9)
163+
// 状态(si = 5, pi = 9)
164+
// 状态(si = 6, pi = 9)
165+
//
166+
// 求状态(si = 2, pi = 7)时,假设状况如下
167+
// str : a a a a b ...
168+
// si : 2 3 4 5 6 ...
169+
// pat : a * ? ...
170+
// pi : 7 8 9 ...
171+
// 状态(si = 2, pi = 7)的底层会依赖:
172+
// 状态(si = 2, pi = 9)
173+
// 状态(si = 3, pi = 9)
174+
// 状态(si = 4, pi = 9)
175+
// 状态(si = 5, pi = 9)
176+
// 状态(si = 6, pi = 9)
177+
//
178+
// 注意看状态(si = 2, pi = 7)底层依赖的后4个,其实就是状态(si = 3, pi = 7)
179+
// 所以,状态(si = 2, pi = 7)的底层依赖可以化简为:
180+
// 状态(si = 2, pi = 9)、状态(si = 3, pi = 7)
181+
// 这样枚举行为就被化简成了有限两个状态,详细情况看代码
182+
public static boolean process3(char[] str, char[] pattern, int si, int pi) {
183+
if (si == str.length && pi == pattern.length) {
184+
return true;
185+
}
186+
if (si == str.length) {
187+
return (pi + 1 < pattern.length && pattern[pi + 1] == '*') && process3(str, pattern, si, pi + 2);
188+
}
189+
if (pi == pattern.length) {
190+
return false;
191+
}
192+
if (pi + 1 >= pattern.length || pattern[pi + 1] != '*') {
193+
return ((str[si] == pattern[pi]) || (pattern[pi] == '.')) && process3(str, pattern, si + 1, pi + 1);
194+
}
195+
// 此处为斜率优化,含义看函数注释
196+
if ((str[si] == pattern[pi] || pattern[pi] == '.') && process3(str, pattern, si + 1, pi)) {
197+
return true;
198+
}
199+
return process3(str, pattern, si, pi + 2);
200+
}
201+
202+
// 以下的代码是斜率优化后的尝试函数,改成动态规划的解
203+
// 请先理解基础班中"暴力递归改动态规划"的内容
204+
// 如果str长度为N,pattern长度为M,最终时间复杂度为O(N*M)
205+
public static boolean isMatch4(String str, String pattern) {
206+
if (str == null || pattern == null) {
141207
return false;
142208
}
143209
char[] s = str.toCharArray();
144-
char[] e = exp.toCharArray();
145-
if (!isValid(s, e)) {
210+
char[] p = pattern.toCharArray();
211+
if (!isValid(s, p)) {
146212
return false;
147213
}
148-
boolean[][] dp = initDPMap(s, e);
149-
for (int i = s.length - 1; i > -1; i--) {
150-
for (int j = e.length - 2; j > -1; j--) {
151-
if (e[j + 1] != '*') {
152-
dp[i][j] = (s[i] == e[j] || e[j] == '.') && dp[i + 1][j + 1];
214+
int N = s.length;
215+
int M = p.length;
216+
boolean[][] dp = new boolean[N + 1][M + 1];
217+
dp[N][M] = true;
218+
for (int j = M - 1; j >= 0; j--) {
219+
dp[N][j] = (j + 1 < M && p[j + 1] == '*') && dp[N][j + 2];
220+
}
221+
// dp[0..N-2][M-1]都等于false,只有dp[N-1][M-1]需要讨论
222+
if (N > 0 && M > 0) {
223+
dp[N - 1][M - 1] = (s[N - 1] == p[M - 1] || p[M - 1] == '.');
224+
}
225+
for (int i = N - 1; i >= 0; i--) {
226+
for (int j = M - 2; j >= 0; j--) {
227+
if (p[j + 1] != '*') {
228+
dp[i][j] = ((s[i] == p[j]) || (p[j] == '.')) && dp[i + 1][j + 1];
153229
} else {
154-
int si = i;
155-
while (si != s.length && (s[si] == e[j] || e[j] == '.')) {
156-
if (dp[si][j + 2]) {
157-
dp[i][j] = true;
158-
break;
159-
}
160-
si++;
161-
}
162-
if (dp[i][j] != true) {
163-
dp[i][j] = dp[si][j + 2];
230+
if ((s[i] == p[j] || p[j] == '.') && dp[i + 1][j]) {
231+
dp[i][j] = true;
232+
} else {
233+
dp[i][j] = dp[i][j + 2];
164234
}
165235
}
166236
}
167237
}
168238
return dp[0][0];
169239
}
170240

171-
public static boolean[][] initDPMap(char[] s, char[] e) {
172-
int slen = s.length;
173-
int elen = e.length;
174-
boolean[][] dp = new boolean[slen + 1][elen + 1];
175-
dp[slen][elen] = true;
176-
for (int j = elen - 2; j > -1; j = j - 2) {
177-
if (e[j] != '*' && e[j + 1] == '*') {
178-
dp[slen][j] = true;
179-
} else {
180-
break;
181-
}
182-
}
183-
if (slen > 0 && elen > 0) {
184-
if ((e[elen - 1] == '.' || s[slen - 1] == e[elen - 1])) {
185-
dp[slen - 1][elen - 1] = true;
186-
}
187-
}
188-
return dp;
189-
}
190-
191241
}

src/topinterviewquestions/Problem_0010_RegularExpressionMatching2.java

Lines changed: 0 additions & 118 deletions
This file was deleted.

0 commit comments

Comments
 (0)