这道题是一道类似正则表达式匹配的题目,但是我发现这个题的难度比之前那个题的难度高几个档次。如题目所示:'?'可以匹配任意一个字符,而 ' * ' 则可以匹配任意一个字符串,给你两个字符串,主串和模式串,判断他们是否可以匹配。
这道题的难度在于‘*’的处理,到底‘*’要和多少个字符串匹配呢?这个问题不好解决,我一开始的思路是:
1.遇到s[i] = p[i] || p[i] =='?' 这两种情况,两者都前进一位
2.遇到s[i] != p[i] 的时候,看前面是否有‘*’,若无则直接返回false,若有的话就比较麻烦了...
3.遇到p中的‘*’时,在p后面找一个字符串,找其在s中第一次出现的下标,继续;若失败则回溯,找第二次出现的下标...
这样的思路会用到KMP算法,而且回溯的位置也太难控制,所以我决定放弃,我又想了很久,没有思路,后来不得不看看网友的思路,在他们的解题中,我发现了,这个题需要明白一件事!
好了讲到这里就比较清晰了,看代码吧!
class Solution {
public:
bool isMatch(string s, string p)
{
/*
这道题要想清楚思路,我一开始的思路是遇到*号的时候,在s[i~s.s.len]内查找p[i~p[j] == '*' || p[j] == '?'] 第一次出现的位置,这样比较好判断是否需要继续比较了,但是这样无疑引入了KMP算法,想到这样我就觉得这样的做法不可取,kmp算法本来就比较复杂的,再引入它的话,就加大了难度,这个题和以前做过的正则表达式有些相似,但是这个题却比那个题难,主要是对 * 的分析比较麻烦,这道题采用了循环的做法,因为我感觉若*号太多的话,递归的层数太多了,效率也会被拖下来的。
*/
return Match(s.c_str(), p.c_str());
}
bool Match(const char* s, const char* p)
{
const char * back = NULL; //用于标记S中和 P中'*'号对应的位置,从该位置起开始依次查找回溯。
const char * sequence = NULL; //标记P中 '*' 出现的位置
while (*s)
{
if (*p == '*')
{ //若 p 中出现了 ‘*’,则back记录s与其对应的位置(可能是空串),sequence 记录'*'的下一个位置,因为从下一个位置开始查找的
back = s;
sequence = ++p;
}
else if (*p == '?' || *s == *p)
{// 这两种情况的话,则 s 和 p 的位置各加1
++s;
++p;
}
else if (sequence)
{//说明出现了 '*' 且在查找中不匹配,那么s应该指向back的下一个位置,p 回到原来位置'*'的下一个位置
s = ++back;
p = sequence;
}
else
{//没有出现‘*’且不匹配,那么可以直接下结论了,退出!
return false;
}
}
while(*p == '*')
{// p的序列中‘*’可能出现在末尾,那么我们应该跳过这些位置
++p;
}
// 最后通过p是否指向最后一个位置来说明true或者false
return (*p == '\0');
}
};
结果如下: