给定一个字符串 (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()];
    }

 

posted on 2018-05-28 11:13  Mini_Coconut  阅读(189)  评论(0编辑  收藏  举报