package 第01期.mca_test; // 测试链接 : 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; } char[] s = str.toCharArray(); char[] e = exp.toCharArray(); return isValid(s, e) && process(s, e, 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)) { return true; } si++; } return process(s, e, si, ei + 2); } // 改记忆化搜索+斜率优化 public static boolean isMatch2(String str, String exp) { if (str == null || exp == null) { return false; } 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); } public static boolean process2(char[] s, char[] e, int si, int ei, int[][] dp) { if (dp[si][ei] != 0) { return dp[si][ei] == 1; } boolean ans = false; if (ei == e.length) { ans = si == s.length; } 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); } 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); } } } } dp[si][ei] = ans ? 1 : -1; return ans; } // 动态规划版本 + 斜率优化 public static boolean isMatch3(String str, String pattern) { if (str == null || pattern == null) { return false; } 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] == '.'); } 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]; } else { if ((s[i] == p[j] || p[j] == '.') && dp[i + 1][j]) { dp[i][j] = true; } else { dp[i][j] = dp[i][j + 2]; } } } } return dp[0][0]; } }