zoukankan      html  css  js  c++  java
  • 正则表达式匹配(剑指offer_19)

    题目描述


    请实现一个函数用来匹配包括 '.'  和 '*' 的正则表达式。模式中的字符'.'表示任意一个字符,而 '*' 表示它前面的字符可以出现任意次(包含0次)。

    在本题中,匹配是指字符中的所有字符匹配整个模式。例如,字符串 “aaa” 与模式 “a.a” 和 “ab*ac*a” 匹配,但是与“aa.a”和“ab*a”均不匹配。

    解题思路


    应该注意到,'.' 是用来做一个任意字符,而 '*' 是用来重复前面的字符。 这两个的作用不同,不能把 '.' 的作用和 '*' 进行类比,从而把它当成重复前面字符一次。

    1.分析题目

    • 输入:一个待匹配字符串,一个待匹配正则表达式
    • 输出:字符串与正则表示式相匹配则输出true,否则输出false
    • 条件:正则表达式中仅含两个特殊字符;.表示任意一个字符,*表示它前面的字符能够出现0~无数次。题目未说明是否贪心匹配(即尽可能多的匹配)的情况下,应默认非贪心匹配。即应考虑类似aaaa*aa相匹配的情况。同时注意可能会出现.*这类能够匹配所有字符的表达式。

    2.可能出现的情况
    考虑字符串和正则相匹配时能够相消去,则当最终两者为空时为匹配成功;中途有不匹配且不带*的字符或是最终不能相互消去时为匹配失败。这种情况很显然使用指针移动特别好用。
    考虑情况如下:

    • 字符串空时,正则式不为空。后者剩余字符若皆为带/*字符,则应继续消去。
    • 当前指针指向字符能够消去时(正则式当前指针字符与字符串当前指针字符相同,或是正则式当前指针字符为.且字符当前指针不为),需要考虑正则指针的下一步指向是否为*。为*则需要考虑此时是否非贪心匹配。
    • 当前指针指向字符不可相互消去时,需考虑正则指针下一步指向是否为*,为*则可忽略正则指针此时的不匹配字符,令其向前移两位;否则直接匹配失败。例如aaaab*c*aa能匹配成功。

    3.思考解题步骤
    在2中所考虑的情况都能够用起初的思路--指针移动解决,故确定以指针为解题方向。
    同时,每一步对于当前指针指向字符的处理过程都是相似的,故考虑使用递归使代码更加简洁。
    很惭愧,在编写2中指针字符相互消去的情况时,我发现自己写的代码总是会遗漏部分情况,查看错误样例后发现对*的非贪心匹配处理要写出大量逻辑繁琐且容易出错的代码。在查看讨论区的解答后,发现自己一直走了死胡同。对于这种问题应考虑使用动态规划的思想,将情况一分为二的处理,分别计算继续判断当前*与结束当前*匹配的情况。

    public boolean match(char[] str, char[] pattern) {
    
        int m = str.length, n = pattern.length;
        boolean[][] dp = new boolean[m + 1][n + 1];
    
        dp[0][0] = true;
        for (int i = 1; i <= n; i++)
            if (pattern[i - 1] == '*')
                dp[0][i] = dp[0][i - 2];
    
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++)
                if (str[i - 1] == pattern[j - 1] || pattern[j - 1] == '.')
                    dp[i][j] = dp[i - 1][j - 1];
                else if (pattern[j - 1] == '*')
                    if (pattern[j - 2] == str[i - 1] || pattern[j - 2] == '.') {
                        dp[i][j] |= dp[i][j - 1]; // a* counts as single a
                        dp[i][j] |= dp[i - 1][j]; // a* counts as multiple a
                        dp[i][j] |= dp[i][j - 2]; // a* counts as empty
                    } else
                        dp[i][j] = dp[i][j - 2];   // a* only counts as empty
    
        return dp[m][n];
    }
  • 相关阅读:
    Spring MVC学习03页面跳转
    Spring Boot学习07配置加载顺序
    Spring MVC学习01从空白Maven项目搭建环境
    Spring MVC学习05JSON序列化
    剑指Offer 44 数字序列中某一位的数字
    Spring MVC学习06异常解析器
    MSSQL·查看DB中所有表及列的相关信息
    MSSQL·查询数据库中所有索引的相关信息
    MSSQL·最长输出长度限制之解决方案
    .Net Core·热加载的实现及测试
  • 原文地址:https://www.cnblogs.com/ziytong/p/12114952.html
Copyright © 2011-2022 走看看