干tm的算法2:正则表达式匹配

题目

给你一个字符串 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 = “cab” 输出:true 解释:因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’
被重复一次。因此可以匹配字符串 “aab”。 示例 5:

输入:s = “mississippi” p = “misisp*.” 输出:false

提示:

0 <= s.length <= 20 0 <= p.length <= 30 s 可能为空,且只包含从 a-z 的小写字母。 p
可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 保证每次出现字符 * 时,前面都匹配到有效的字符

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目很好,可以当做某些数据进行匹配。也类似按某个匹配规则进行数据处理。不过这个题目提示到了正则的高度,可能比较通用化。通用化意味着包容性要强,也就是长度从0到无穷大都应该匹配上。

那么走二条路子。
对应是java 作业先交。是一个评论里面老哥写的比较好的

class Solution {
    public boolean isMatch(String s, String p) {
        if (s == null || p == null) return false;

        int m = s.length(), n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];
        dp[0][0] = true;
        
        //"" 和p的匹配关系初始化,a*a*a*a*a*这种能够匹配空串,其他的是都是false。
        //  奇数位不管什么字符都是false,偶数位为* 时则: dp[0][i] = dp[0][i - 2]
        for (int i = 2; i <= n; i+= 2) {
            if (p.charAt(i - 1) == '*') {
                dp[0][i] = dp[0][i - 2];
            }
        }

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                char sc = s.charAt(i - 1);
                char pc = p.charAt(j - 1);
                if (sc == pc || pc == '.') {
                    dp[i][j] = dp[i - 1][j - 1];
                } else if (pc == '*') {
                    if (dp[i][j - 2]) {
                        dp[i][j] = true;
                    } else if (sc == p.charAt(j - 2) || p.charAt(j - 2) == '.') {
                        dp[i][j] = dp[i - 1][j];
                    }
                }
            }
        }

        return dp[m][n];
    }
}

然后我们来解读老哥的代码:

class Solution {
    public boolean isMatch(String s, String p) {
        /* 1.最基本的情况,其中一个有,另外一个完全没有,那么这二个字符串铁定不会匹配上 */
        if (s == null || p == null) return false;
        /* 获取对应字符串的长度 */
        int m = s.length(), n = p.length();
        /* 初始 对应一个boolean 二维数组  对应值是对应长度+1  前面一个是S 另外一个是P */
        boolean[][] dp = new boolean[m + 1][n + 1];
        /** 这里初始值 00 是true  这里类似赋值一个初始值,然后后面沿用 类似初始值是 true */
        dp[0][0] = true;
        
        //"" 和p的匹配关系初始化,a*a*a*a*a*这种能够匹配空串,其他的是都是false。
        //  奇数位不管什么字符都是false,偶数位为* 时则: dp[0][i] = dp[0][i - 2]

        /** 亮点  老哥这里的解释我觉得OJBK  存在匹配空串如果匹配上,必定是*号把前一位的进行对冲了。也就是利用* 标识匹配0个前面元素特性进行抵消 */

        for (int i = 2; i <= n; i+= 2) {
            if (p.charAt(i - 1) == '*') {
                dp[0][i] = dp[0][i - 2];
            }
        }

        /** 重头分析 : 上面优先排除集中极为特殊的情况,下面就是正常情况,区别在于多少问题
        正常分析 
          */
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                /** 获取要对比的字符 chanAt 获取对应下标 */
                char sc = s.charAt(i - 1);
                char pc = p.charAt(j - 1);
                /** 简简单单的 如果对应字符匹配或者是. 万能匹配 那么对应就是OK 沿用之前的boolean dp [i-1][j-1] 就是最开始的00  就是ture 或者 有些地方的false */
                if (sc == pc || pc == '.') {
                    dp[i][j] = dp[i - 1][j - 1];
                } else if (pc == '*') {
                    /** 如果对应 pc是*  那么就是再前一位 对比值  如果dp[i][j - 2]  不正确那么进行下面的判断  */
                    if (dp[i][j - 2]) {
                        dp[i][j] = true;
                    } else if (sc == p.charAt(j - 2) || p.charAt(j - 2) == '.') {
                        /** 这二个判断应该是这里的核心关键  也就是动态规划的对比点  
                        如果这上面的值对等,那么下面感觉还是差点东西。
                        我再领悟一下
                         */
                        dp[i][j] = dp[i - 1][j];
                    }
                }
            }
        }

        return dp[m][n];
    }
}

官方分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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)) {
                        f[i][j] = f[i][j] || f[i - 1][j];
                    }
                } 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) {
            return false;
        }
        if (p.charAt(j - 1) == '.') {
            return true;
        }
        return s.charAt(i - 1) == p.charAt(j - 1);
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/regular-expression-matching/solution/zheng-ze-biao-da-shi-pi-pei-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

时间复杂度:O(mn)O(mn),其中 mm 和 nn 分别是字符串 ss 和 pp 的长度。我们需要计算出所有的状态,并且每个状态在进行转移时的时间复杂度为 O(1)O(1)。

空间复杂度:O(mn)O(mn),即为存储所有状态使用的空间。

以上是对应官方解题思路。
不能都凭自己的理解去阅读一些东西,更需要有一个明确的官方的来引导自己的解题思路。
后续有新的理解,再做补充


漫漫长路,一个小周跟他一个小陈朋友一起努力奔跑。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值