思路:贪心
1.假设p格式为”*p1*p2*p3*“,其中pi代表一个被分割的子串,我们只需要在s当中找到相应子串便可匹配成功了。比如说s=“abcdefgabc”,p=“bcdfgb*”,那么我们只需要按pi的相对顺序到s当中找到相应子串即可匹配成功。
2.然而p也可能表示为”p0*p1*p2*p3*p4“,这样的话,我们得保证s当中必须以p0开头而且以p4结尾。
3.为了保证以p4结尾,我们从后开始遍历s和p,令i=s.size()-1,j=p.size()-1,如果s[i]p[j]或者p[j]’?’,则分别从s和p中弹出匹配的字符,直到找到p串当中最后一个‘*’,这样我们保证了p的格式为”p0*p1*p2*p3*“。
4.然后我们设置pStart=0,代表当前p正在匹配的子串pk的起始位置,sStart=-1,代表s正在与p子串pk匹配的起始位置,为什么sStart=-1呢?因为p的开始可能就是‘*’。
5.令i=0,j=0,开始从头匹配s和p
- 如果p[j]==’*’,也就是找到了一个p子串 p k p_k pk,我们那么我们更新p下一个子串 p k + 1 p_{k+1} pk+1的匹配起始位置为j+1,将pStart更新为j+1,然后j=pStart;这时因为s[i]并没有与p的任何字符匹配所以,i不变,但是sStart需要更新为sStart。
- 如果s[i]s[j]或者p[j]’?’,也就是两个字符匹配,i++,j++,比较下一对字符。
- 如果此时s[i]和s[j]匹配不上,这时我们需要考虑当前匹配的子串 p k 是 否 为 p 0 p_{k}是否为p_0 pk是否为p0
- 当k==0时,如果p的起始不为‘*’,那么匹配将失败。
- 当k!=0时,我们需要更新s当中子串开始匹配的位置,令sStart++,然后i=sStart,j=pStart,重新开始比较s[i]和p[j]。
代码:
class Solution {
public:
bool isMatch(string s, string p) {
int i=s.size()-1;
int j=p.size()-1;
for(;i>=0&&j>=0;i--,j--)
{
if(p[j]=='*')
{
break;
}
else if(s[i]!=p[j]&&p[j]!='?')
{
return false;
}
else
{
s.pop_back();
p.pop_back();
}
}
i=j=0;
int sStart=-1;//当前s子串开始匹配位置,从-1开始是因为p的开始可能是*
int pStart=0;//当前p子串开始匹配的位置
if(p.empty())
return s.empty();
while(i<s.size()&&j<p.size())
{
if(p[j]=='*')
{
sStart=i;
j++;
pStart=j;
}
else if(s[i]==p[j]||p[j]=='?')
{
i++;
j++;
}
else if(sStart!=-1)
{
sStart++;
i=sStart;
j=pStart;
}
else
{
return false;
}
}
while(j<p.size())
{
if(p[j++]!='*')
return false;
}
return true;
}
};