正则表达式匹配

解题思路

  1. 找到子问题
  • if p[i]= s[j] or p[i] ='.' : match(s[0..j-1],p[0..i-1])
    else return false
  • if p[i] = '' : match(s[0..j] ,p[0..i-1]) // is empty
    or p[i-1]p[i] = c* , match(s[0..j-x] ,p[0..i-2]) ,
    x 代表c* 能最大匹配的长度 '' 'c' ,'cc' 'ccc' , 这里的问题是不定匹配所有的c , 所以用 |=
  1. 设dp[i][j] = match(s[0..j],p[0..i]) ,从左到右 ,从上到下进行遍历
  • 对 dp[i][0]的情况应该 单独初始化,因为 p= "a*" 匹配 s= '' *
  • ".*" 都能匹配 "ab" 的话 说明这是一种很强大的组合,应该单独讨论 *

代码

class Solution {
public:
    bool isMatch(string s, string p) {
            //   找到子问题
            // if p[i]= s[j] or p[i] ='.' :    match(s[0..j-1],p[0..i-1])
            // else return false
            // if p[i] = '*'  :  match(s[0..j] ,p[0..i-1])  //* is empty  
            //
                // or   p[i-1]p[i] = c* ,  match(s[0..j-x] ,p[0..i-2])  ,x 代表c* 能最大匹配的长度  '' 'c' ,'cc' 'ccc'

        //     设dp[i][j]  =  match(s[0..j],p[0..i]) 
        //     从左到右 ,从上到下进行遍历
        //     举例验证
        //        a a a
        //      1 0 0 0     
        //    a 0 1 0 0  
        //    b 0 0 0 0 
        //    * 0 1 0 0 
        //    a 0 0 1 0  

        //程序输出DP
        // 1 0 0 0 
        // 0 1 0 0 
        // 0 0 0 0 
        // 0 1 0 0 
        // 0 0 1 0 


        std::vector< std::vector<int> > dp(p.size()+1, std::vector<int> (s.size()+1,0));
        dp[0][0] =1;
        // 应用offset法  s[j] p[i] 对应dp[i+1][j+1]
        //如何初始化 dp[n][0]  
        for(int n=1;n<= p.size() ;n++)
        {
            // p[n-1] = c or . , dp[n][0] =0
            // else *  即 能否与空字符串匹配
                // dp[n][0]  = dp[n-2][0]  
            if(n>1 && p[n-1]== '*') dp[n][0]  = dp[n-2][0];
            else if(p[n-1]== '*') dp[n][0]=1;
            else dp[n][0]=0;
        }
       
        
        for(int i=0;i<p.size();i++)
        {
            for(int j=0;j<s.size();j++)
            {
                if(p[i]==s[j] || p[i] == '.' )
                {
                    dp[i+1][j+1] = dp[i][j];
                }else if(p[i] == '*')
                {
                    // p[i-1] vs s[j]  0 1 ,2
                    int x=0;

                    if(i>0)  //类似 *ac * 只能匹配0 个 s
                    {
                        //关于.* ,如果.只能代表一种字符 如匹配aaa  VS .* 
                        //        char target=p[i-1];
                        // if(p[i-1] == '.')  target=s[j];    //    寻找 s[...j] 第一个不等于s[j]
                        // int tJ = j;
                        // while(tJ>=0 && s[tJ] == target )
                        // {
                        //     x++;
                        //     tJ--;
                        // } 
                        //但".*" 都能匹配 "ab" 的话 说明这是一种很强大的组合 
                       if(p[i-1] == '.')  
                        {
                            // 尝试找到 dp[i-2][j-y] 
                            // 其中y 1 0 0 0 第一个1出现的位置 
                            // 即如果 发现dp[i-2][...j)] 中有1存在 则 dp[i][j]=1 
                            int m=j+1;
                           for(;m>=0;m--)
                           {
                               if(dp[i-1][m])  break;
                           }
                           if(m<0) dp[i+1][j+1]=0;
                           else dp[i+1][j+1]=1;
                        }else
                        {
                            int tJ = j;
                            //这里的问题是不定匹配所有的c , 所以用 |= 
                            while(tJ>=0 && s[tJ] == p[i-1] )
                            {
                                dp[i+1][j+1] |= dp[i-1][j+1-x];
                                x++;
                                tJ--;
                            } 
                             dp[i+1][j+1] |= dp[i-1][j+1-x];

                            
                        }
                    }else  dp[i+1][j+1] = dp[i-1][j+1-x];
                   
                }else
                {
                    dp[i+1][j+1] =0;
                }
            }
        }

    //   for(auto vec: dp)
    //   {
    //       for(auto x: vec) std::cout<< x <<" ";
    //       std::cout << std::endl;
    //   }

        return dp[p.size()][s.size()];

       //eg2
        //     a b
        //   1 0 0  
        // . 0 1 0 
        // * 0 1 1

        //eg3
        //     a a b
        //   1 0 0 0
        // c 0 0 0 0 
        // * 1
        // a
        // *
        // b
        // *
      //exe output
    //     1 0 0 0 
    // 0 0 0 0 
    // 1 0 0 0 
    // 0 1 0 0 
    // 1 1 1 0 
    // 0 0 0 1 


    }
};

题目描述

请实现一个函数用来匹配包含'. '和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

示例 1:

输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:

输入:
s = "aa"
p = "a"
输出: true
解释: 因为 '
' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:

输入:
s = "ab"
p = "."
输出: true
解释: ".
" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:

输入:
s = "aab"
p = "cab"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:

输入:
s = "mississippi"
p = "misisp*."
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 ,无连续的 ''。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

posted @ 2021-05-15 15:57  boyang987  阅读(40)  评论(0编辑  收藏  举报