「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
题目描述
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1:
输入:s = "aa" p = "a" 输出:false 解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa" p = "a*" 输出:true 解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
解题思路
递归
分析:因为模板pattern有两个不同状态‘’和‘.’,所以我们以模板字符串来考虑递归条件,主要有以下三种情况:
- 模板串>=2且第二个为,组成为: ch,* 和 .,*
- 模板>=2 ch,ch 和 .,ch 和 ch,. 和 .,.
- 模板=1 (等于0时候在函数入口就处理了) ch 和 .
class Solution {
public boolean isMatch(String s, String p) {
if (s == null || p == null) {
return false;
}
//需要分别取出s和p为空的情况,所以memo数组大小+1
Boolean[][] memo = new Boolean[s.length() + 1][p.length() + 1];
return isMatch(s, 0, p, 0, memo);
}
private boolean isMatch(String s, int sIndex, String p, int pIndex, Boolean[][] memo) {
if (sIndex == s.length() && pIndex == p.length()) {
return true;
}
if (pIndex == p.length() && sIndex < s.length()) {
return false;
}
if (memo[sIndex][pIndex] != null) {
return memo[sIndex][pIndex];
}
boolean ret = false;
if (pIndex + 1 < p.length() && p.charAt(pIndex + 1) == '*') {
if (sIndex < s.length() && ((s.charAt(sIndex) == p.charAt(pIndex) || p.charAt(pIndex) == '.'))) {
ret = isMatch(s, sIndex + 1, p, pIndex, memo) || isMatch(s, sIndex, p, pIndex + 2, memo);
} else {
ret = isMatch(s, sIndex, p, pIndex + 2, memo);
}
} else {
if (pIndex < p.length() && sIndex < s.length() && (s.charAt(sIndex) == p.charAt(pIndex) || p.charAt(pIndex) == '.')) {
ret = isMatch(s, sIndex + 1, p, pIndex + 1, memo);
} else {
ret = false;
}
}
memo[sIndex][pIndex] = ret;
return ret;
}
}
动态规划
dp[i][j] 表示s的前i个字符和p的前j个字符是否匹配。那么,主要分两种情况。
- 匹配0个,也就是
dp[i][j] == dp[i][j-2] - 匹配多个,
dp[i][j] = dp[i-1][j]表示即可。
public boolean isMatch(String s, String p) {
if (s == null || p == null || (!p.isEmpty() && p.charAt(0) == '*')) {
return false;
}
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int i = 0; i < n; i++) {
//"a*b*c*d"
if (p.charAt(i) == '*' && dp[0][i - 1]) {
dp[0][i + 1] = true;
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
//s: abcd
//p: abc.
if (p.charAt(j) == s.charAt(i) || p.charAt(j) == '.') {
dp[i + 1][j + 1] = dp[i][j];
} else if (p.charAt(j) == '*'){
//递归公式
//s: abcd
//p: abcdd*
if (p.charAt(j - 1) == s.charAt(i) || p.charAt(j - 1) == '.') {
dp[i + 1][j + 1] = dp[i][j + 1];
}
//s: abcd
//p: abcde*
dp[i + 1][j + 1] |= dp[i + 1][j - 1];
}
}
}
return dp[m][n];
}