zoukankan      html  css  js  c++  java
  • leetcode problem 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
    


    有两种方法, 一种是递归直接匹配,比较好理解,代码简洁。
          另一种是DP,时间复杂度小 ,为O(m*n) 其中m是匹配串长度,n是模式串长度。

    先说第一种:
        设S为匹配串,P为模式串,令i指向匹配串Si,令j指向模式串Pj,判断P[j+1]是否为* 如果不是*,判断S[i] == P[j] ? 如果等于,则递归处理S[i+1] P[j+1],不等于则返回false。如果P[j+1]是*,则需要综合考虑两种情况,一个是*表示前一个字符重复0次,
      另一种情况是前一个字符重复 >=1次的情况,并对这两种情况取"或"。 看代码很容易理解的

    Runtime: 40 ms
    #define ISMATCH(a, b) (a != '' && (a == b || b == '.'))
    
    class Solution {
    public:
        bool isMatch(const char *s, const char *p, int i = 0, int j = 0) {
            if (p[j] == '') 
                return s[i] == '';
            if (p[j+1] != '*') 
                return ISMATCH(s[i], p[j]) && isMatch(s, p, i+1, j+1);
            if (p[j+1] == '*') {
                return     //0 times
                    isMatch(s, p, i, j+2) ||
                        // more times 
                    (ISMATCH(s[i], p[j]) && isMatch(s, p, i+1, j));
            }
            return false;
        }
    };
    第二种方法用的是动态规划,非常巧妙。时间复杂度比较低为O(m*n)
      令dp[i][j]表示匹配串S[1..i]是否与模式串P[1..j]匹配。 dp[i][j] = true表示匹配,dp[i][j] = false表示不匹配,状态转移方程可以写成这样:

               dp[i][j-2]                 if P[j] == '*' 考虑*表示重复前一字符为0次的情况
        dp[i][j] = dp[i][j-1]                  if P[j] == '*' 考虑*表示重复前一字符为1次的情况(注意这里不用重复字符大于一次的情况,因为其实将来的状态矩阵中已经保存了的, 如dp[i][j]表示重复一次的情况且P[j] = '*', 那么dp[i+1][j]表示重复2次的情况,
                                                                dp[i+2][j]表示重复3次的情况,一次类推.)
               dp[i-1][j-1] && S[i] == S[j]       if P[j] != '*'


    其实只要理解了dp[i][j]表示什么意思,就很好解释了。
    代码如下(做了一些优化,本来状态矩阵需要DP[m][n]的空间代价的,但是由于状态转移方程中在获得dp[i][j]时只用到了dp[i][j-2],所以可以只用dp[1..n]来维护状态)
    Runtime: 10 ms
    #define ISMATCH(a, b) (a == b ||(a != '' && b == '.'))
    
    
    class Solution {
    public:
        bool isMatch(const char *s, const char *p) {
            int lenS = strlen(s);
            int lenP = strlen(p);
    
            vector<bool> dp(lenS+1, false);
            dp[0] = true;
    
            for (int j = 0; j < lenP; ++j) {
                if (j+1 < lenP && p[j+1] == '*')
                    continue;
                if (p[j] == '*') {
                    for (int i = 1; i <= lenS; ++i) {
                        dp[i] = dp[i] || (dp[i-1] && ISMATCH(s[i-1], p[j-1]));
                    }
                }
                else {
                    for(int i = lenS; i > 0; --i) {
                        dp[i] = dp[i-1] && ISMATCH(s[i-1], p[j]);
                    }
                    dp[0] = false;
                }
            }
            return dp[lenS];
        }
    };


  • 相关阅读:
    EF 配置实现建表与迁移
    微服务
    CentOS 系统管理与yum软件仓库搭建
    CentOS 网络操作
    CentOS 进程操作
    CentOS 用户/组与权限
    C# 三个Timer
    Entity Framework 小知识(四)
    Entity Framework 索引
    Entity Framework 小知识(三)
  • 原文地址:https://www.cnblogs.com/lysuns/p/4434569.html
Copyright © 2011-2022 走看看