44. Wildcard Matching

此道题目,我一开始用的是递归,发现超时,然后就用了二维DP,发现还是超时,最后加了一点trick,勉强才过,不过时间复杂度很高。最理想的方法应该是贪心加回溯。算法思想如下。

Analysis:


For each element in s
If p[j]==s[i] or p[j] == ? which means this is a match, then goes to next element i++ j++.
If p[j]=='*', this is also a match, but one or many chars may be available, so let us save this *'s position and the matched s position.
If not match, then we check if there is a * previously showed up,
       if there is no *,  return false;
       if there is an *,  we set current p to the next element of *, and set current s to the next saved s position.

e.g.

abed
?b*d**

a=?, go on, b=b, go on,
e=*, save * position starIndex=3, save s position iIndex = 3, j++
e!=d,  check if there was a *, yes, ++iIndex, s=iIndex; p=starIndex+1
d=d, go on, meet the end.
check the rest element in p, if all are *, true, else false;
在这里需要注意的一点是,这种解法之所以要比递归快,是利用了一个巧妙之处。在递归中, 每一个‘*’都会产生一些分支,所有‘*’产生的分支都会被回溯直到发现match为止;而用这个方法只会回溯最后一个‘*’的分支,不会继续往上。把这个结构看成一棵树,这个方法只回溯最后一层。可以这样理解这一点:假设在s和p进行匹配的过程中,遇到了两个*,用A和B分别表示它们的位置,我们担忧的一点是,到达B处时,我们修改iIndex和starIndex,但是万一我们需要在A处回溯怎么办?而这个时候,在A处的*的位置信息已经完全被覆盖掉了。这种情况可能存在么?答案是不存在。由程序逻辑可知,在B处之前,s和p已经完全匹配。假如需要在A处回溯,也就是A处的*应该匹配更多的字符,这说明在s中有一些字符需要被消化掉,那么B处的*就可以做到这一点,而不必在A处回溯,以使A处的*匹配更多的字符。代码如下:

class Solution {
public:
    bool isMatch(string s, string p) {
        int i = 0;
        int j = 0;
        int starIndex = -1;
        int iIndex = -1;
        
        while (i < s.length()) {
            if (j < p.length() && (p[j] == '?' || p[j] == s[i])) { // match
                ++i;
                ++j;
            } else if (j < p.length() && p[j] == '*') {
                starIndex = j; // 记录*的位置
                iIndex = i; // 记录i的位置
                j++; // 从j下一个位置进行匹配, *匹配了0个字符
            } else if (starIndex != -1) { // 如果之前有*出现过,则回溯
                j = starIndex + 1; // 重置j的位置
                i = iIndex+1;
                iIndex++; // *匹配1,2,3,4,5...个字符
            } else {
                return false; // 不match,return false
            }
                
            
        }
        
        while (j < p.length() && p[j] == '*') { // 看p剩下的字符是不是都是*
            ++j;
            
        }
                
        return j == p.length();
        
    }
                
    
};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值