LeetCode(44) Wildcard Matching

题目:

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

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", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
问号可以匹配任意一个字符,星号可以匹配任意多个字符。判断两个字符串是否能匹配。

解法:这道题比较难,我一开始用回溯法超时了。看了别人的做法,是用贪心加回溯。

参考:http://blog.csdn.net/wusecaiyun/article/details/47024765

基本思路:


当S没有结束时,


1、如果P没结束且 (P[j]==?或者S[i]=P[j]),那么就是普通匹配,i++,j++。


2、如果P没结束且P[j]==*。记下这时的i和j的值,j++。

     ( 这时还是匹配的,但是*号可以和任意长度字符串匹配,因此需要使用回溯法。

      我们从'*'与0个字符匹配开始尝试,如果后面匹配失败,就回到这个地方,再尝试把'*'与1个字符匹配、与2个字符匹配,...

      为了能回到*的位置,需要记录下来星号匹配时的i和j的值。然后先从与0个字符匹配开始尝试,所以j++,i不变。

      下一次再回到这里时,让i和j变回这个时候的i和j的值,因为要比之前多匹配一个字符,所以i++,j++,还要更新i的记录值。)


3、如果上面两个不成立,检查之前是否有出现“*”。如果有,让i和j等于记录的i和j值,i++,j++,把i的记录值改为现在的i的值。


如果上面3条都不成立,匹配失败。


当S结束后,检查P剩余部分是否全部都是*。如果剩下都是*,匹配成功,否则失败。


        这样的做法和单纯回溯法的不同点是,这种做法的回溯只回到遍历过的最后一个‘*’的位置,不需要回到之前的‘*’。

        之所以能这么做,是因为尝试匹配的字符数是从少到多的:

        假如有两个“*”,分别在位置A和B,A在B前面。如果B后面的字符匹配失败,只需要回溯到B,不需要回溯到A。因为匹配到B后面的字符才失败,说明B处之前,S和P完全匹配。如果后面不能匹配,那么说明P的B处及之前这一整段需要匹配S中更多的字符。因为B处之前已匹配,所以只要让B处的‘*’与更多S中的字符匹配就可以了,不用回溯到A。其实回溯到A的作用是要让AB这一段能匹配上S,遇到B处的‘*’就无需回到A处。

        如果我们一开始尝试星号匹配的时候不是从少到多,就需要回溯到前面的‘*’了。因为这个时候出现不匹配,可能需要让P的前B个字符匹配S中更少的字符。但是B处的‘*’最少也要匹配0个字符,如果B处不能减少匹配的字符数,就一定要回到A处去减少。而如果匹配从少到多,那么需要增加多少,都可以在B处完成,不需要回到A。(当然如果还没有匹配到B,是要回到A的。一旦匹配到B,就不需要回到A了。)


代码:

class Solution {
public:
    bool isMatch(string s, string p) {
        int i=0,j=0;
        int savei,savej=-1;/*savej是*在p中的位置,savei是s与*匹配后,i的位置*/
        while(i<s.length())
        {
            if(j<p.length()&&(s[i]==p[j]||p[j]=='?')) {i++;j++;}//正常匹配
            else if(j<p.length()&&p[j]=='*') {savej=j;savei=i;j++;}/*星号匹配,星号从0个元素开始匹配,所以j加1,i不变*/
            else if(savej!=-1)//回溯
            {/*回溯时,i回到savei,j回到savej,然后因为星号多匹配一个元素,所以i和j都加1*/
                i=savei+1;
                j=savej+1;
                savei=i;//savei记录新的匹配后i的位置
            }
            else return false;
        }
        
        //s结束后,只有当p剩下的都是*才能匹配
        while(j<p.length()&&p[j]=='*') j++;
        if(j==p.length()) return true;
        else return false;
        
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值