• [Leetcode] 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

    题意:' . '能匹配任意字符,‘ * ‘表示之前的那个字符可以是0个、1个或者多个,(注意:s= ba和 p= a*bc也是匹配的,*表示p中 * 之前的字符为0个,但s=‘bc’和 p=‘aa*bc’是不匹配的)。

    思路:根据字符' * '的特殊性,整体的解决方法主要是分两种情况:

    一、p的第二个字符*(p+1)不是 ' * ',这种情况,只要存在 *s==*p 或者*p=' . '中的一种情况,就说明当前p 和 s 对应的字符匹配,就可以比较两个的下一个字符(这有一个前提,就是 s 要不为空,要是 s 为空了,就不匹配了,不用继续比较了);

    二、p的第二个字符*(p+1)是 ' * ',这种情况就比较麻烦了,也分两种情况:

      1) 在*s==*p 或者*p==' . '其中的一种情况下,判断 ' * '是代表0个、1个或者多个前一个字符,如何去实现了?先将 *s 和*(p+2)去匹配,看是否能匹配,若能代表*表示0个之前字符,若是不能,则将s++,然后和P接着匹配,看是否匹配,若是,则将 *s 和*(p+2)去匹配继续上部分的循环;若不是,则直接将 *s 和*(p+2)去匹配,不用继续判断*s和*p是否匹配。是有点绕口,结合代码看,可能稍微好些。如:s= aba和 p= a*ba或者s= aab和 p= a*bc

      2)*s !=*p 和*p !=' . ',说明,p中的第一个字符,在s中不存在,直接说明 ' * '代表0个之前的字符,那么就继续判断 *s 和*(p+2)是否匹配。如s= ba和 p= a*bc是匹配,s= ba和 p= a*cbc则是不匹配,但是说明依旧说明在开始判断时,' * '代表0个 a。

    结合 : 当p为空,若s也为空,返回true,反之返回false; 当p的长度为1,若s长度也为1,且相同或是p为'.'则返回true,反之返回false;代码如下:

     1 class Solution {
     2 public:
     3     bool isMatch(const char *s, const char *p) 
     4     {
     5         if(*p=='')    return *s=='';
     6         if(*(p+1) =='*')
     7         {
     8             while(*p==*s||(*p=='.'&&*s !=''))
     9             {
    10                 if(isMatch(s++,p+2))    //判断*之前元素的个数
    11                     return true;
    12             }
    13             return isMatch(s,p+2);      //直接匹配字符*的下一个
    14         }
    15         else
    16         {
    17             if(*p==*s||(*p=='.'&&*s !=''))
    18                 return isMatch(s+1,p+1);
    19             return false;
    20         }
    21     }
    22 };

     
    还有一种利用动态规划的方法,暂时没有看太懂,这里给出链接1 ,链接2,方便以后揣摩。

     再次看题时,看到这里有动态规划的解法,就结合LeetCode给出了自己的理解,具体分析过程参见上面的递归,这里仅给出状态转移方程的解释,其中dp[i[[j]是表示s[0,i)和p[0,j)相匹配(注意区间前闭后开)

    j注意二维数组下标和字符串下表的对应关系

    (1)当字符串p中当前字符不是‘*’时,对dp[i][j]只要此时字符串s、p对应匹配,则dp[i][j]的状态应和dp[i-1][j-1]一样,即:

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

    (2)当字符串p中当前字符是‘*’时,有两种情况:

      (a)该字符'*'只代表0个前一个字符,所以当前的dp值要看同行中前两列的值,则:

      dp[i][j]=dp[i][j-2] 

     (b) 该字符'*'只代表一个或多个前一个字符时,p中*对应的s中的字符要和p中*之前的字符向匹配,即s中有多个*之前的字符,只有这样才可能代表多个,这时也要考虑p中*和之前的是否和s中,对应之前的相匹配。

    感觉说不清了,好绕,举个例子:s="aaab",p="a*b",p[1]=* 了,此时*代表多个p[0] (设代表n个),所以要考虑,s中是否有多个a啊,所以把p[0]和s[1]对比,发现匹配,那这时是不是说明两者相匹配了?不一定,如:s="baab",b="a*b",p[0]和s[1]匹配,而两字符串不匹配,即我们还要考虑s[0]和p[0]与p[1]组合的字符串是否匹配,即*代表n-1个是否匹配。

        dp[i][j] = i>0&&(s[i-1]==p[j-2]||p[j-2]=='.')&&dp[i-1][j]

    s="aaab",p="a*b"时,列为p,行为s二维矩阵为:

      “” a * b
    "" T F T F
    a F T T F
    a F F T F
    a F F T F
    b F F F T

     代码如下:

     1 class Solution {
     2 public:
     3     bool isMatch(const char *s, const char *p) 
     4     {
     5         int slen=strlen(s),plen=strlen(p);
     6         vector<vector<bool>> dp(slen+1,vector<bool>(plen+1,false));
     7 
     8         dp[0][0]=true;
     9 
    10         for(int i=0;i<slen+1;i++)
    11         {
    12             for(int j=1;j<plen+1;++j)
    13             {
    14                 if(p[j-1]=='*')
    15                     dp[i][j]=dp[i][j-2]||(i>0&&(s[i-1]==p[j-2]||p[j-2]=='.')&&dp[i-1][j]);
    16                 else
    17                     dp[i][j]=i>0&&dp[i-1][j-1]&&(s[i-1]==p[j-1]||p[j-1]=='.');
    18 
    19             }
    20         }    
    21         return dp[slen][plen];    
    22     }
    23 };

    个人建议:画出矩阵看

  • 相关阅读:
    导数,微积分,牛顿运动学制作创意地图
    逻辑回归的算法思想
    偏导数
    POJ2112:Optimal Milking(Floyd+二分图多重匹配+二分)
    POJ2289:Jamie's Contact Groups(二分+二分图多重匹配)
    HDU3829:Cat VS Dog(最大独立集)
    POJ2594:Treasure Exploration(Floyd + 最小路径覆盖)
    HDU1151:Air Raid(最小边覆盖)
    HDU1054 Strategic Game(最小点覆盖)
    POJ3020:Antenna Placement(二分图匹配)
  • 原文地址:https://www.cnblogs.com/love-yh/p/7076444.html
Copyright © 2020-2023  润新知