zoukankan      html  css  js  c++  java
  • 10. Regular Expression Matching

    题目:
    LeetCode:10. Regular Expression Matching

    描述:

    Implement regular expression matching with support for '.' and '*'.

    '.' Matches any single character.
    '*' Matches zero or more of the preceding element.
    
    The matching should cover the entire input string (not partial).
    
    The function prototype should be:
    bool isMatch(const char *s, const char *p)
    
    Some examples:
    isMatch("aa","a") → false
    isMatch("aa","aa") → true
    isMatch("aaa","aa") → false
    isMatch("aa", "a*") → true
    isMatch("aa", ".*") → true
    isMatch("ab", ".*") → true
    isMatch("aab", "c*a*b") → true
    

    大体意思和正则匹配很相似,但不同的是* 是匹配前一个字符的。开始的时候理解错了题意走了弯路,虽然还是可以做的。。。。。

    分析:

    1.暴力枚举的办法:

     // 思路:
    // 1、s、p从0开始相互匹配,当且仅当p匹配至结尾时,s也匹配至结尾后才显示匹配成功;
    // 2.1 判断p是否匹配至结尾,若为结尾判断s是否为结尾。
    // 2.2 判断当前索引的下一字符是否为'*':
    // 2.2.1 若下一字符不为'*',则判断当前字符是否匹配成功p[nIndexP] == '.' || p[nIndexP] == s[nIndexS]
    // 2.2.1.1 当前字符匹配成功则两字符串索引累加,递归匹配下一字节是否匹配;
    // 2.2.1.2 若匹配失败,返回匹配失败;
    // 2.2.2 若下一字符为'*',则将递归匹配 nIndexP + 2 字符与 s字符串的剩余部分。
    // 2.2.2.1 成功则匹配成功,失败则回溯当前状态;
    // 2.2.2.2 失败回溯则,s字符串累加1后,继续重复2.2.2步骤。
    // 2.2.2.3 直至* 将所有s中与前一字符相同的字符全部匹配,匹配p中'*'后剩余字符串与s剩余字符串递归2.1步骤
    // 备注:若为正则表达式则此处为匹配任意字符都可以,而不是匹配p的前一字符
    // 2.2.2 若下一字符为'*',则判断(p[nIndexP] == '.' || p[nIndexP] == s[nIndexS] && nIndexS < s.size()))
    // 依次匹配s的字符,直至匹配到s字符不等于p当前字符或s结尾部分。
    // 若下一字符为'*',则用 匹配 nIndexP + 2 字符与 s字符串的剩余部分进行匹配,若匹配成功,则成功。
    // 反之累加s字符索引,右移一个位重复是
    // 2.2.2.1 则判断当前字符是否相等 并且 nIndexS是否越界
    

    2.使用动态规划的方法,讨论Si与Pi的匹配问题,列出状态转移方程,完成设计。由于对动态规划理解不够深刻,所以专门补习了一下,详细可参考白话算法之动态规划

    代码:

    思路一:递归方式,160ms左右

    bool match(string s, string p, int nIndexS, int nIndexP)
    {
        // p 是否匹配到结尾,当且仅当 s、p同时到结尾部分才匹配成功
        int nLenS = s.length();
        int nLenP = p.length();
        if (nIndexP == nLenP)
        {
            return nIndexS == nLenS;
        }
        if (p[nIndexP + 1] != '*')
        {
            if (p[nIndexP] == s[nIndexS] || p[nIndexP] == '.')
            {
                ++nIndexP;
                ++nIndexS;
                return match(s, p, nIndexS, nIndexP);
            }
            return false;
        }
        else
        {
            while (p[nIndexP] == s[nIndexS] || p[nIndexP] == '.' && nIndexS < nLenS)
            {
                if (match(s, p, nIndexS, nIndexP + 2))
                {
                    return true;
                }
                // * 匹配掉相同字符
                ++nIndexS;
            }
            return match(s, p, nIndexS, nIndexP + 2);
        }
    }
    bool isMatch(string s, string p)
    {
        return match(s, p, 0, 0);
    }
    
    

    思路二:动态规划方式

    bool isMatch1(string s, string p) {
        int slen = s.size();
        int plen = p.size();
        vector<vector<bool>> dp(slen + 1, vector<bool>(plen + 1, false));
        dp[0][0] = true;
        for (int i = 0; i <= slen; ++i) {
            for (int j = 1; j <= plen; ++j) {
                if (p[j - 1] == '*') {
                    dp[i][j] = dp[i][j - 2] || (i > 0 && (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);
                }
                else dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.');
            }
        }
        return dp[slen][plen];
    }
    

    备注:
    后续会补充对动态规划方法的解法,在本题中动态规划效率极高。

  • 相关阅读:
    Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur
    Luogu 4514 上帝造题的七分钟
    Luogu 1484 种树
    Luogu【P2904】跨河(DP)
    Luogu【P2065】贪心的果农(DP)
    Luogu【P1725】琪露诺(单调队列,DP)
    二分图匹配
    单调队列
    Tarjan的强联通分量
    手写堆
  • 原文地址:https://www.cnblogs.com/liuwfuang96/p/6906600.html
Copyright © 2011-2022 走看看