这是我在leetcode上做的第一道hard难度的题,最终还是看了讨论区的做法才做出来。这题的意思是,给两个字符串s和p,判断它们是否是完全匹配,其中p中的*可以代表任意长度的任意字符,?代表某个字符。完全匹配返回true,否则返回false。这题乍看很简单(最终答案也不长),但其中有许多需要考虑的问题,稍有不慎一些测试样例就过不去了。在不断碰壁之后,我发现这些问题都是出在*这个字符上,或者更直白一点,就是*应该代表s中哪段字符才合适。
先说解题思路,可以先用两个变量(i和j)存储s和p中要检查的字符的位置,将s中的字符和p中的字符进行一一比较,相同或者p中字符是?则i++,j++。如果不是,情况就分为三种:(1).p[j]是*;(2).p[j]越界或者p[j]未越界但不为*,但是字符串p的前面位置出现了*;(3).p[j]不是*并且前面也没有*,那么s和p不能完全匹配。
由此可见,三种情况之中,第一种和第二种较为棘手。考虑到*是空串的情况,遇到情况(1)时,i不需要变化,但需要j++(解决”a”和”*?*”的情况)。为了不让p中的*代表的字符串过短,我们需要记录最近的一个*出现的位置(starIndex),在每次遇到第一种情况时都进行记录,以便我们在遇到第二种情况的时候,可以通过这个记录,将检查的p中的字符位置返回到*的后一个位置,继续进行匹配。这样就可以解决一些如”abefcdgiescdfimde”和”ab*cd?i*de”的匹配。而另外还有个问题,比如”aa”和”*”,匹配完s第1个a之后,p中字符位置就越界了,但是i并没有增加,则j会变为1,i依旧不会变化,这样就形成了死循环。因此我们还需要记录最近的一次和*匹配的s中字符的位置(match),在进行情况(3)处理的时候将i赋值为match+1,然后增加match。
实现代码如下
class Solution {
public:
bool isMatch(string s, string p) {
int j = 0;
int i = 0;
int starIndex = -1;
int match;
while (i < s.size()) {
if((j < p.size())&&((s[i] == p[j])||(p[j] == '?'))) {
i++;
j++;
} else {
if ((j < p.size())&&(p[j] == '*')) {
starIndex = j;
match = i;
j++;
} else {
if (starIndex != -1) {
j = starIndex + 1;
match++;
i = match;
} else return false;
}
}
}
while ((j < p.size())&&(p[j] == '*')) {
j++;
}
return (j == p.size());
}
};