作者:whisper
链接:https://www.proprogrammar.com/article/893
声明:请尊重原作者的劳动,如需转载请注明出处
正则中的?*匹配,利用动态规划实现;难度:困难;标签;编程语言:JAVA
给定一个字符串 (s
) 和一个字符模式 (p
) ,实现一个支持 '?'
和 '*'
的通配符匹配。
两个字符串完全匹配才算匹配成功。
说明:
示例 1:
输入: s = "aa" p = "a" 输出: false 解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入: s = "aa" p = "*" 输出: true 解释: '*' 可以匹配任意字符串。
示例 3:
输入: s = "cb" p = "?a" 输出: false 解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
示例 4:
输入: s = "adceb" p = "*a*b" 输出: true 解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
示例 5:
输入: s = "acdcb" p = "a*c?b" 输出: false
class Solution {
int[] post;
Boolean[][] dp;
public boolean isMatch(String s, String p) {
p = p.replaceAll("\\*{2,}", "*");
post = new int[p.length()+1];
dp = new Boolean[s.length()+1][p.length()+1];
for(int i = p.length()-1; i >= 0; i--){
if(p.charAt(i) != '*')post[i] = post[i+1]+1;
else post[i] = post[i+1];
}
return isMatch(s, p, 0, 0);
}
private boolean isMatch(String s, String p, int si, int pi){
// System.out.println(s+" "+p+" "+si+" "+pi);
if(dp[si][pi] != null)return dp[si][pi];
if(s.length()-si < post[pi])dp[si][pi] = false;
else if(pi == p.length() && si == s.length())dp[si][pi] = true;
else if(si == s.length()){
if(p.charAt(i) != '*'){
dp[si][pi] = false;
return dp[si][pi];
}
dp[si][pi] = true;
}else if(pi == p.length()){
dp[si][pi] = false;
}else{
if(p.charAt(pi) == '?')dp[si][pi] = isMatch(s, p, si+1, pi+1);
else if(p.charAt(pi) == '*'){
dp[si][pi] = isMatch(s, p, si+1, pi) || isMatch(s, p, si, pi+1);
}else dp[si][pi] = p.charAt(pi) == s.charAt(si) && isMatch(s, p, si+1, pi+1);
}
return dp[si][pi];
}
}
记忆化+深搜的dp做法,有两处优化的地方,第一如果p串剩余的非*字符数大于s串剩余字符数,那么return false,第二多个连续的*可以当成是一个*,
其中状态转移方程是dp[si][pi] = isMatch(s, p, si+1, pi) || isMatch(s, p, si, pi+1);如果当前是*,那么可以不用,转移到isMatch(s, p, si, pi+1),也可以使用(匹配s当前位置的一个任意字符),转移到isMatch(s, p, si+1, pi),而且s下个位置与p当前位置同样进行前面的判断,这样递归下去,一个*可以匹配0个,1个,。。。。个s中的字符,实现了匹配任意个字符的效果
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int i = 1; i <= n; ++i) {
if (p.charAt(i - 1) == '*') {
dp[0][i] = true;
} else {
break;
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
} else if (p.charAt(j - 1) == '?' || s.charAt(i - 1) == p.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
}
动态规划,具体分析看题解吧,其实还有另一种贪心方法,也在题解中,但分析起来更难,还是自己看吧
亲爱的读者:有时间可以点赞评论一下
月份 | 原创文章数 |
---|---|
202205 | 1 |
202204 | 1 |
202203 | 11 |
202201 | 2 |
202108 | 7 |
202107 | 3 |
202106 | 16 |
202105 | 10 |
202104 | 16 |
202103 | 56 |
202102 | 14 |
202010 | 3 |
202009 | 3 |
202008 | 7 |
202007 | 7 |
202006 | 10 |
202005 | 11 |
202004 | 22 |
202003 | 52 |
202002 | 44 |
202001 | 83 |
201912 | 52 |
201911 | 29 |
201910 | 41 |
201909 | 99 |
201908 | 35 |
201907 | 73 |
201906 | 121 |
201811 | 1 |
201810 | 2 |
201804 | 1 |
201803 | 1 |
201802 | 1 |
201707 | 1 |
全部评论