zoukankan      html  css  js  c++  java
  • Leetcode(10)-正则表达式匹配

    给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。

    '.' 匹配任意单个字符。
    '*' 匹配零个或多个前面的元素。
    

    匹配应该覆盖整个字符串 (s) ,而不是部分字符串。

    说明:

    • s 可能为空,且只包含从 a-z 的小写字母。
    • p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *

    示例 1:

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

    示例 2:

    输入:
    s = "aa"
    p = "a*"
    输出: true
    解释: '*' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 "aa"。
    

    示例 3:

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

    示例 4:

    输入:
    s = "aab"
    p = "c*a*b"
    输出: true
    解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 "aab"。
    

    示例 5:

    输入:
    s = "mississippi"
    p = "mis*is*p*."
    输出: false

    思路:如果不用递归的方法,一点一点的判断,比如如果当前的p[j]为*,那么如果s的当前值与p[j-1]相等,就i++。这样存在的问题是,不能判断出*到底代替几个p[j-1],所以我们还是用递归的方法。

     bool isMatch(string s, string p) {  
           
            int pLen=p.length();  
            int sLen=s.length();  
              
            if(pLen==0)  
                return sLen==0;  
                  
            if(pLen==1)  
                if( (s[0]==p[0] || p[0]=='.') && sLen==1)  
                    return true;  
                else  
                    return false;  
                      
            if(p[1]!='*')
            {  
                if(s.length()>0 && (s[0]==p[0] || p[0]=='.'))  
                    return isMatch(s.substr(1),p.substr(1));  
                else  
                    return false;  
            }
            else
            {  
                while(s.length()>0 && (p[0]==s[0] || p[0]=='.'))  
                {  
                    if(isMatch(s,p.substr(2)))//*表示0个字符  
                        return true;  
                    s=s.substr(1);  
                }  
                return isMatch(s,p.substr(2));  
            }  
        }  
    上述程序就将*分成了两种情况,一种是*代表0个字符,一种是*代表1个或多个字符。首先每次判断代表0个字符是否符合,如果不符合,那么就先代表一个,将s的首字符去掉,接着判断,这样*就代表了一个或多个。
    还有一种DP的思路,是用空间换时间。额外申请一个数组作为辅助,记录前面的结果。dp[i][j]代表s[0..i-1]和p[0...j-1]的匹配,0代表匹配失败,1代表匹配成功。那么可以得到,dp[0][0]=1表示空串与空串是匹配的,dp[i][0]=0,表示如果p是空串,那么一定不匹配。dp[0][j]表示s是空串,这种情况如果p是x*的组合,是可以匹配的,否则匹配失败。而且dp[0][1]=0表示如果s为空串,p只有一个字符时,肯定匹配失败。dp[i][j]我们可以分为p[j-1]为*和不为*的情况,(1)如果p[j-1]也就是p的最后一个元素为*,那么还可以分为它代表0个前面的元素,也就是说s[0..i-1]与p[0..j-3]是要匹配的,即dp[i][j-2]=1。或者它代表一个或多个前面的元素,那么s[0..i-2]与p[0..j-1]是匹配的,并且s的最后一个元素s[i-1]还要与p的倒数第二个相等,即s[i-1]==p[i-2].
      bool isMatch(string s, string p)
      {
          int m=s.size()+1,n=p.size()+1;
          vector<vector<bool> > dp(m,vector<bool>(n));
            dp[0][0] = true;//s无字符,p无字符
            dp[0][1] = false;//s无字符,p有一个字符(且不能省略)
            for (int i = 1; i <= s.size(); ++i)
                dp[i][0] = false;//s有字符,p无字符
            for (int j = 2; j <= p.size(); ++j)//Ax*只有A与空串匹配,且后两个字符是x*的形式才匹配
                dp[0][j] = (p[j - 1] == '*') && dp[0][j - 2];
            for (int j = 1; j <= p.size(); ++j)
                for (int i = 1; i <= s.size(); ++i) {
                    if (p[j - 1] != '*') //如果不是*,只有p遍历到.或者p[j-1]和s[i-1]相等的时候匹配
                        dp[i][j] = dp[i - 1][j - 1] && (p[j - 1] == '.' || s[i - 1] == p[j - 1]);
                    else dp[i][j] = dp[i][j - 2] ||//x*表示0个x的情况
                        (dp[i - 1][j - 2] && (p[j - 2] == '.' || p[j - 2] == s[i - 1])) ||//x*表示1个x的情况
                          //x*表示多个x的时候表示,此时必须s[0~i-2]与p[0~j-1]匹配且……
                        (dp[i - 1][j] && (p[j - 2] == '.' || p[j - 2] == s[i - 1]));
                }
            return dp[s.size()][p.size()];
        }
  • 相关阅读:
    一个母亲一生撒的八个谎言(含泪推荐)!
    穷人必须做的四件大事
    八种人不太可能驰骋职场,有你吗?
    是谁让我如此忧伤?
    拒绝平淡:我用十年的时间名满天下
    高性能利器!华为云MRS ClickHouse重磅推出!
    MySQL 连接为什么挂死了?
    解读登录双因子认证(MFA)特性背后的TOTP原理
    云图说|初识数据仓库服务:云时代的数据分析助手
    号外!5G+X联创营华为云官网上线,5G 创业春天来了!
  • 原文地址:https://www.cnblogs.com/mini-coconut/p/9099112.html
Copyright © 2011-2022 走看看