通知
关于网站更多信息请加whimurmur模板/jpress插件QQ群(1061691290)            网站从因情语写改为晴雨            这个网站的模板也从calmlog_ex改为 whimurmur

正则表达式 leetcode 44. 通配符匹配

248人浏览 / 0人评论 / | 作者:whisper  | 分类: 正则表达式  | 标签: 正则表达式专栏  | 

作者:whisper

链接:https://www.proprogrammar.com/article/893

声明:请尊重原作者的劳动,如需转载请注明出处


正则中的?*匹配,利用动态规划实现;难度:困难;标签;编程语言:JAVA


44. 通配符匹配

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。

两个字符串完全匹配才算匹配成功。

说明:

  • s 可能为空,且只包含从 a-z 的小写字母。
  • p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。

示例 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];
    }
}

动态规划,具体分析看题解吧,其实还有另一种贪心方法,也在题解中,但分析起来更难,还是自己看吧

通配符匹配


亲爱的读者:有时间可以点赞评论一下

点赞(0) 打赏

全部评论

还没有评论!
广告位-帮帮忙点下广告