zoukankan      html  css  js  c++  java
  • 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)确定边界的值

    2)动态规划推导方程

    http://blog.csdn.net/fzzying3/article/details/42057935

    这里我们对该动态规划解法进行一定的分析说明,

    这里我们采用b[i+1][j+1]代表s[0..i]匹配p[0..j]的结果,结果自然是采用布尔值True/False来表示。

    1.因此,首先是对边界进行赋值,显然b[0][0] = true,两个空字符串的匹配结果自然为True

    接下来,我们对b[i+1][0]进行赋值,显然对于空的匹配串,b[i+1][0]的数值必须为False

    接着,我们对b[0][j+1]进行赋值,其值等于j > 0 && '*' == p[j] && b[0][j - 1],

    1.首先是j>0,原因很简单,如果j=0则b[0][1]表示空的原串匹配长度为1的匹配串,无论长度为1的匹配串

    为何种字符串,其结果都为false,试想一下,如果匹配串为一个字母字符自不必多说,如果为"."也容易理解,

    如果为“*”,则是无效字符串,因为本题要求"*"之前必须要有一个字符,所以长度为1的字符串不可能为“*”;

    2.其次'*' == p[j] && b[0][j - 1],如果一个空串和一个匹配串想要匹配成功,那么只有可能是:

    p[0..j-2]匹配空串成功且无论p[j-1]是什么p[j]都必须是'*',所以就是'*' == p[j] && b[0][j - 1]

    前两个边界赋值结束了之后,接下来就是经典的动态规划递推方程了:

    1. 当前匹配串的字符不为’*‘,那么b[i + 1][j + 1] = b[i][j] && ('.' == p[j] || s[i] == p[j]),显然如果当前字符串不为'*',

    则我们需要实打实地对s[i]和p[j]进行匹配,因此很自然s[0..i]和p[0..j]的匹配结果取决于s[0..i-1]和p[0..j-1]的

    匹配结果与上s[i]和p[j]的匹配结果,因此就造就了上式;

    2.若当前匹配串的字符为’*‘,那么b[i + 1][j + 1] = b[i + 1][j - 1] && j > 0 || b[i + 1][j] 

                                                               || b[i][j + 1] && j > 0 && ('.' == p[j - 1] || s[i] == p[j - 1]);

    其意义为s[0..i]和p[0..j]的匹配结果取决于s[0..i]和p[0..j-2]的匹配结果,意味着我们忽略’*‘不重复,

    其次s[0..i]和p[0..j]的匹配结果也可以取决于s[0..i]和p[0..j-1]的匹配结果,意味着我们利用'*'只重复一次,

    再次s[0..i]和p[0..j]的匹配结果也可以取决于s[0..i-1]和p[0..j]以及s[i]和p[j-1]的匹配结果,这个是整个递推

    表达式当中最难理解的部分,其含义是

    如果s[0..i-1]和p[0..j]匹配了,说明当前的’*‘在一个字符之前的原串中已经得到匹配,那么要跟当前这个

    字符匹配则只需要判断当前的s[i]和p[j-1]是否匹配即可,显然j必须要大于0,这里其实暗含了’*‘重复多次

    的情形,试想s[0..i-1]都和p[0..j]匹配了,那么如果当时的匹配是不重复的匹配,那好,那么这次就是重复

    一次的匹配,如果当时是重复n次的匹配,那么经过这次匹配就变成了重复n+1次的匹配了,那么可能有人

    要问了既然第三项包含了重复一次的匹配,为何还需要第二项s[0..i]和p[0..j-1]匹配结果,原因是第三项建立

    在s[0..i-1]和p[0..j]匹配的基础之上,完全有可能s[0..i-1]和p[0..j]不匹配,然而s[0..i]和p[0..j-1]匹配,应该这么说

    ’*‘重复一次的匹配有两种,一种是s[0..i-1]和p[0..j-2]匹配再加上当前s[i]和p[j-1]匹配或者s[0..i]和p[0..j-1]匹配。

    简而言之:

    状态转移方程如下:
    dp[i][j] = 
    c1. p[j+1] != '*'时   if s[i] == p[j]  dp[i][j] = dp[i+1][j+1] 
                           else dp[i][j] = false
    c2 p[j+1] == '*'时  (这个情况下,要扩展 *, dp[i][j] 从拓展的情况下,选择一个是真的结果)
                           if( s[i] ==  p[j] || p[j] == '.' && (*s) != 0)  当s[i] 和 p[j] 一样的时候,例如 aba, a*b这个时候,i = 0, j = 0, 自然可以匹配a a
                                                                                    如果p[j] == .  因为他可以匹配任何字符,所以和相等关系有基本一样的方式。
                           并且每一步匹配都要递增 i 的值,如果有成立的,则返回true,否则到匹配终了,返回通配符匹配完成后的结果。

    bool isMatch(char* s, char* p) {
         int i, j;  
            int m = strlen(s);  
            int n = strlen(p);  
      
            /** 
             * b[i + 1][j + 1]: if s[0..i] matches p[0..j] 
             * if p[j] != '*' 
             * b[i + 1][j + 1] = b[i][j] && s[i] == p[j] 
             * if p[j] == '*', denote p[j - 1] with x, 
             * then b[i + 1][j + 1] is true if any of the following is true 
             * 1) "x*" repeats 0 time and matches empty: b[i + 1][j -1] 
             * 2) "x*" repeats 1 time and matches x: b[i + 1][j] 
             * 3) "x*" repeats >= 2 times and matches "x*x": s[i] == x && b[i][j + 1] 
             * '.' matches any single character 
             */  
            bool b[m + 1][n + 1];  
            b[0][0] = true;  
            for (i = 0; i < m; i++) {  
                b[i + 1][0] = false;  
            }  
            // p[0..j - 2, j - 1, j] matches empty if p[j] is '*' and p[0..j - 2] matches empty  
            for (j = 0; j < n; j++) {  
                b[0][j + 1] = j > 0 && '*' == p[j] && b[0][j - 1];  
            }  
      
            for (i = 0; i < m; i++) {  
                for (j = 0; j < n; j++) {  
                    if (p[j] != '*') {  
                        b[i + 1][j + 1] = b[i][j] && ('.' == p[j] || s[i] == p[j]);  
                    } else {  
                        b[i + 1][j + 1] = b[i + 1][j - 1] && j > 0 || b[i + 1][j] ||  
                                    b[i][j + 1] && j > 0 && ('.' == p[j - 1] || s[i] == p[j - 1]);  
                    }  
                }  
            }  
            return b[m][n];  
    }
    

      

  • 相关阅读:
    3-1
    3-2
    习题二 8
    习题二 3
    习题二 5
    习题二 4
    习题二 6
    实验三-2未完成
    实验三
    心得
  • 原文地址:https://www.cnblogs.com/qiaozhoulin/p/4785077.html
Copyright © 2011-2022 走看看