你先别急咱也在学呢所以没更新完(
KMP
前言:暴力匹配算法
在学习KMP之前,我们首先要解决一个问题:
有两个字符串,一个是主串\(S\),一个是模式串\(P\),\((S.len>P.len)\),要求求出\(P\)在\(S\)中的位置,不存在输出\(-1\).
看到这样的问题,先写一个暴力,时间复杂度统统不管,毕竟都暴力了要啥自行车
我们从第一位开始匹配:
我们设暴力匹配时,\(S\)的枚举位置是\(i\),\(P\)的枚举位置是\(j\)。
\(i==0,j==0\)
\(S\)的第一位是\(B\),\(P\)的第一位是\(A\),不匹配,移动\(i\)向前一位,\(j\)不变为0。
依旧不匹配,向前至匹配时候。
现在\(i==3,j==0\),\(S_3==P_0==A\),匹配上了,\(++i,++j\)。
\(i==4,j==1,S_4==P_1==B\),还在匹配,还在匹配!!!!
\(i==6,j==3,S_6==A,P_3==D\),最后一位没匹配上。。。怎么办?
如果没有匹配上,而且我们还匹配上了几步,肯定不能像之前一样直接\(++i\),必须从零开始,与此同时\(++i\),
操作应为\(i=i-j+1;j=0;\),下一次匹配是这样的:
于是就有了代码:
暴力匹配代码
int ViolentMatch(char* s, char* p)
{
int sLen = strlen(s);
int pLen = strlen(p);
int i = 0;
int j = 0;
while (i < sLen && j < pLen)
{
if (s[i] == p[j])
{
//①如果当前字符匹配成功(即S[i] == P[j]),则i++,j++
i++;
j++;
}
else
{
//②如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0
i = i - j + 1;
j = 0;
}
}
//匹配成功,返回模式串p在文本串s中的位置,否则返回-1
if (j == pLen)
return i - j;
else
return -1;
}
然后这个暴力显然是不够优雅的,我们看我们最后一个匹配例子:
在之前的匹配中我们知道\(i==4,j==1,S_4==P_1==B\neq P_0==A\),i回溯是浪费我们的时间,就应该直接跳到\(i==7,S_7==A\)的正确位置。
1.正确位置在哪里?
这个正确位置,在\(KMP\)中是\(next\).
我们上面找的例子里面模式串\(P\)中没有重复的字符,没有代表性,所以我们重新整一个新的例子:
直接匹配到该回溯的位置:
暴力匹配下一步应该是这样的:
但是我们希望是这样的:
这样是不重不漏的,而且\(i\)也不会回溯。