From 6679ad61f73e41fc4800e444a40522c3044b0fdf Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Thu, 17 Aug 2023 10:55:33 +0800 Subject: [PATCH] modify code --- .../Code04_RegularExpressionMatch.java | 178 ++++++++---------- 1 file changed, 77 insertions(+), 101 deletions(-) diff --git a/大厂刷题班/class12/Code04_RegularExpressionMatch.java b/大厂刷题班/class12/Code04_RegularExpressionMatch.java index c4b35b7..d1b0f23 100644 --- a/大厂刷题班/class12/Code04_RegularExpressionMatch.java +++ b/大厂刷题班/class12/Code04_RegularExpressionMatch.java @@ -3,129 +3,105 @@ package class12; // 测试链接 : https://leetcode.com/problems/regular-expression-matching/ public class Code04_RegularExpressionMatch { - public static boolean isValid(char[] s, char[] e) { - // s中不能有'.' or '*' - for (int i = 0; i < s.length; i++) { - if (s[i] == '*' || s[i] == '.') { - return false; - } - } - // 开头的e[0]不能是'*',没有相邻的'*' - for (int i = 0; i < e.length; i++) { - if (e[i] == '*' && (i == 0 || e[i - 1] == '*')) { - return false; - } - } - return true; - } - - // 初始尝试版本,不包含斜率优化 - public static boolean isMatch1(String str, String exp) { - if (str == null || exp == null) { - return false; - } + // 暴力递归 + public static boolean isMatch1(String str, String pat) { char[] s = str.toCharArray(); - char[] e = exp.toCharArray(); - return isValid(s, e) && process(s, e, 0, 0); + char[] p = pat.toCharArray(); + return process1(s, p, 0, 0); } - // str[si.....] 能不能被 exp[ei.....]配出来! true false - public static boolean process(char[] s, char[] e, int si, int ei) { - if (ei == e.length) { // exp 没了 str? - return si == s.length; - } - // exp[ei]还有字符 - // ei + 1位置的字符,不是* - if (ei + 1 == e.length || e[ei + 1] != '*') { - // ei + 1 不是* - // str[si] 必须和 exp[ei] 能配上! - return si != s.length && (e[ei] == s[si] || e[ei] == '.') && process(s, e, si + 1, ei + 1); - } - // exp[ei]还有字符 - // ei + 1位置的字符,是*! - while (si != s.length && (e[ei] == s[si] || e[ei] == '.')) { - if (process(s, e, si, ei + 2)) { + // s[i....]能不能被p[j....]完全匹配出来 + public static boolean process1(char[] s, char[] p, int i, int j) { + if (i == s.length) { + // s没了 + if (j == p.length) { + // 如果p也没了,返回true return true; + } else { + // 如果p[j+1]是*,那么p[j..j+1]可以消掉,然后看看p[j+2....]是不是都能消掉 + return j + 1 < p.length && p[j + 1] == '*' && process1(s, p, i, j + 2); + } + } else if (j == p.length) { + // s有 + // p没了 + return false; + } else { + if (j + 1 == p.length || p[j + 1] != '*') { + // s[i....] + // p[j....] + // 如果p[j+1]不是*,那么当前的字符必须能匹配:(s[i] == p[j] || p[j] == '?') + // 同时,后续也必须匹配上:process1(s, p, i + 1, j + 1); + return (s[i] == p[j] || p[j] == '.') && process1(s, p, i + 1, j + 1); + } else { + // s[i....] + // p[j....] + // 如果p[j+1]是* + // 选择1: 当前p[j..j+1]是x*,就是不让它搞定s[i],那么继续 : process1(s, p, i, j + 2) + boolean p1 = process1(s, p, i, j + 2); + // 选择2: 当前p[j..j+1]是x*,如果可以搞定s[i],那么继续 : process1(s, p, i + 1, j) + // 如果可以搞定s[i] : (s[i] == p[j] || p[j] == '.') + // 继续匹配 : process1(s, p, i + 1, j) + boolean p2 = (s[i] == p[j] || p[j] == '.') && process1(s, p, i + 1, j); + // 两个选择,有一个可以搞定就返回true,都无法搞定返回false + return p1 || p2; } - si++; } - return process(s, e, si, ei + 2); } - // 改记忆化搜索+斜率优化 - public static boolean isMatch2(String str, String exp) { - if (str == null || exp == null) { - return false; - } + // 记忆化搜索 + public static boolean isMatch2(String str, String pat) { char[] s = str.toCharArray(); - char[] e = exp.toCharArray(); - if (!isValid(s, e)) { - return false; - } - int[][] dp = new int[s.length + 1][e.length + 1]; - // dp[i][j] = 0, 没算过! - // dp[i][j] = -1 算过,返回值是false - // dp[i][j] = 1 算过,返回值是true - return isValid(s, e) && process2(s, e, 0, 0, dp); + char[] p = pat.toCharArray(); + int n = s.length; + int m = p.length; + // dp[i][j] == 0,表示没算过 + // dp[i][j] == 1,表示没算过答案是true + // dp[i][j] == 2,表示没算过答案是false + int[][] dp = new int[n + 1][m + 1]; + return process2(s, p, 0, 0, dp); } - public static boolean process2(char[] s, char[] e, int si, int ei, int[][] dp) { - if (dp[si][ei] != 0) { - return dp[si][ei] == 1; + public static boolean process2(char[] s, char[] p, int i, int j, int[][] dp) { + if (dp[i][j] != 0) { + return dp[i][j] == 1; } - boolean ans = false; - if (ei == e.length) { - ans = si == s.length; + boolean ans; + if (i == s.length) { + if (j == p.length) { + ans = true; + } else { + ans = j + 1 < p.length && p[j + 1] == '*' && process2(s, p, i, j + 2, dp); + } + } else if (j == p.length) { + ans = false; } else { - if (ei + 1 == e.length || e[ei + 1] != '*') { - ans = si != s.length && (e[ei] == s[si] || e[ei] == '.') && process2(s, e, si + 1, ei + 1, dp); + if (j + 1 == p.length || p[j + 1] != '*') { + ans = (s[i] == p[j] || p[j] == '.') && process2(s, p, i + 1, j + 1, dp); } else { - if (si == s.length) { // ei ei+1 * - ans = process2(s, e, si, ei + 2, dp); - } else { // si没结束 - if (s[si] != e[ei] && e[ei] != '.') { - ans = process2(s, e, si, ei + 2, dp); - } else { // s[si] 可以和 e[ei]配上 - ans = process2(s, e, si, ei + 2, dp) || process2(s, e, si + 1, ei, dp); - } - } + ans = process2(s, p, i, j + 2, dp) || ((s[i] == p[j] || p[j] == '.') && process2(s, p, i + 1, j, dp)); } } - dp[si][ei] = ans ? 1 : -1; + dp[i][j] = ans ? 1 : 2; return ans; } - // 动态规划版本 + 斜率优化 - public static boolean isMatch3(String str, String pattern) { - if (str == null || pattern == null) { - return false; - } + // 动态规划 + public static boolean isMatch3(String str, String pat) { char[] s = str.toCharArray(); - char[] p = pattern.toCharArray(); - if (!isValid(s, p)) { - return false; - } - int N = s.length; - int M = p.length; - boolean[][] dp = new boolean[N + 1][M + 1]; - dp[N][M] = true; - for (int j = M - 1; j >= 0; j--) { - dp[N][j] = (j + 1 < M && p[j + 1] == '*') && dp[N][j + 2]; - } - // dp[0..N-2][M-1]都等于false,只有dp[N-1][M-1]需要讨论 - if (N > 0 && M > 0) { - dp[N - 1][M - 1] = (s[N - 1] == p[M - 1] || p[M - 1] == '.'); + char[] p = pat.toCharArray(); + int n = s.length; + int m = p.length; + boolean[][] dp = new boolean[n + 1][m + 1]; + dp[n][m] = true; + for (int j = m - 2; j >= 0; j--) { + dp[n][j] = p[j + 1] == '*' && dp[n][j + 2]; } - for (int i = N - 1; i >= 0; i--) { - for (int j = M - 2; j >= 0; j--) { - if (p[j + 1] != '*') { - dp[i][j] = ((s[i] == p[j]) || (p[j] == '.')) && dp[i + 1][j + 1]; + for (int i = n - 1; i >= 0; i--) { + for (int j = m - 1; j >= 0; j--) { + if (j + 1 == p.length || p[j + 1] != '*') { + dp[i][j] = (s[i] == p[j] || p[j] == '.') && dp[i + 1][j + 1]; } else { - if ((s[i] == p[j] || p[j] == '.') && dp[i + 1][j]) { - dp[i][j] = true; - } else { - dp[i][j] = dp[i][j + 2]; - } + dp[i][j] = dp[i][j + 2] || ((s[i] == p[j] || p[j] == '.') && dp[i + 1][j]); } } }