力扣题10正则表达式匹配(困难)

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例 1:

输入:s = "aa" p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa" p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

示例 3:

输入:s = "ab" p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

示例 4:

输入:s = "aab" p = "c*a*b"
输出:true
解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。示

例 5:

输入:s = "mississippi" p = "mis*is*p*."
输出:false

1.自己在做的时候是从前往后一个个进行比较,但是当遇到"aaa"和"aa*aa"这种情况时就比较难判断了,因为从正向判断无法直接得出这个*的组合匹配了几次,情况比较复杂。因此自己写出来的程序总是有情况没有考虑到,此时应该考虑从后往前进行匹配。

2.动态规划的思想。想成先判断每个子串的匹配情况,再根据当前对应的字符来判断当前字符串的匹配情况。

   查看别人写的分析贴:力扣

   这里贴一个评论区写的代码,来自@huwd

class Solution {
    public boolean isMatch(String s, String p) {
        char[] sChar = s.toCharArray();
        char[] pChar = p.toCharArray();

        //表示前几个字符匹配成功,所以长度分为是sLength+1 和 pLength+1
        boolean[][] f = new boolean[sChar.length + 1][pChar.length + 1];

        f[0][0] = true;//当两个字符串均为空时,也是匹配成功
        //当s不为空时,p为空,则为false,即f[][0] = false;

        //当s为空,如果p都是*组成的组合的话,也可能是true
        for(int j = 1;j <= pChar.length;j++){
            if(pChar[j - 1] == '*'){//p遇到的是*
                f[0][j] = f[0][j-2];//因为s为空,说明该*组成的组合出现0次,所以减2
            }
        }

        //自下而上找出每一个子字符串的匹配结果
        for(int i = 1;i <= sChar.length;i++){
            for(int j = 1;j <= pChar.length;j++){
                if(sChar[i - 1] == pChar[j - 1] || pChar[j-1] == '.'){//字符匹配成功,或者字符是.
                    f[i][j] = f[i-1][j-1];
                }else if(pChar[j - 1] == '*'){//如果遇到*
                    if(sChar[i-1] == pChar[j-2] || pChar[j-2] == '.'){//如果字符匹配成功,或者字符是.
                        f[i][j] = f[i][j-2] //*组合匹配0次
                                || f[i-1][j]; //匹配1次或多次
                    }else{//*字符匹配不成功,说明只能这个*组合只能匹配0次
                        f[i][j] = f[i][j-2];
                    }
                }
            }
        }

        return f[sChar.length][pChar.length];
    }
}

   动态规划的思想就是把大问题化成小问题,然后从小问题一步一步推出大问题的结果。 这题中的难点就是遇到*后的匹配问题,可能匹配0次,也可能匹配多次,所以从后往前来逐个判断比较简单。

   官方解法:

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();

        boolean[][] f = new boolean[m + 1][n + 1];
        f[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (p.charAt(j - 1) == '*') {//如果遇到了*
                    f[i][j] = f[i][j - 2];//把*的组合当成整体
                    if (matches(s, p, i, j - 1)) {//判断*前一个字符和s的字符的匹配情况
                        f[i][j] = f[i][j]//*组合匹配0次的情况 
                                  || f[i - 1][j];//*组合匹配1次或多次
                    }
                } else {//遇到的不是*
                    if (matches(s, p, i, j)) {
                        f[i][j] = f[i - 1][j - 1];//子串就是各自往前移一个字符
                    }
                }
            }
        }
        return f[m][n];
    }

    public boolean matches(String s, String p, int i, int j) {
        if (i == 0) {//如果s是空串,肯定是匹配失败的
            return false;
        }
        if (p.charAt(j - 1) == '.') {//遇到.,任意字符都能匹配
            return true;
        }
        return s.charAt(i - 1) == p.charAt(j - 1);//遇到普通字符,直接比较即可
    }
}

题源:力扣

上一篇:forEach是否会改变原数组


下一篇:搜索题目 专项题解