优质的博客、视频讲解
视频:https://www.bilibili.com/video/av3246487?from=search&seid=16000927909169712834
讲述很详细,包括对next数组的理解(到现在还有点迷糊)、next的作用、next中i、j的跳跃取值等等讲的十分详细。
博客:https://blog.csdn.net/luoshengkim/article/details/44724981
写的非常详细,但是不如视频中的实例讲的更容易理解。
(注意上边视频和博客构造next数组的方式有些不同:视频中的next)
大致过程理解
得到一个next数组
1、含义:是在这个元素前面所形成的区间的这个 子串(或叫子数组区间)的最长的并且相同的前缀后缀的长度,赋到这个next数组。
理解前缀后缀:abcbcb =>前缀a ab abc…… 后缀=>b cb bcb……
2、例子:(就拿b站视频中的例子做例子(例子都举得非常好,很帮助理解,但由于自己鰔鶸还是理解的不好。)=>但是得到next数组的思路是我看博客的理解。)
模板串(也就是短的那个字符串(数组)):1 1 2 1 1 2 1 1 1
首先令next[0]=-1;
然后遍历模板串(数组),next[1] = 0 (因为再1前面形成的区间相同的前缀后缀==1)。next[2] = 1 (因为2前面的区间1 1 有一个共同的前缀后缀,故等于1。)
next[3] = 0; next[4] = 1; next[5] = 2; next[6] = 3; next[7] = 4; next[8] = 5;
3、模板:
void getnext(){
int j=0,k=-1;
next[0]=-1;
while(j<m){
if(k==-1||p[j]==p[k]){ //p为模板串
j++;
k++;
next[j]=k;
}
else
k=next[k];
}
}
4、时间复杂度:O(n)……n为模板串的长度。
运用kmp搜索对原串和模板串(原数组和模板数组)进行搜索匹配
1、过程:遍历两个串会分别有一个位置值:
如果原串[原串的位置值]==模板串[模板串的位置值] =>位置都往后移。
如果原串[原串的位置值]!=模板串[模板串的位置值]=>
①如果暴力搜(bf):让原串的位置退回到与相对于模板串的开头的位置。
②如果kmp:让原串的位置退回到与相对月模板串开头的前缀相同的后缀的位置。(减少遍历次数。)
2、时间复杂度:O(m)……m为原串的长度。
3、模板:匹配输出位置,不匹配输出-1
int kmp(){
int i=0,j=0;
getnext();
while(i<n){
if(j==-1||s[i]==p[j]){ //s为原串 p为模板串
i++;
j++;
}
else
j=next[j];
if(j==m) //m为模板串的长度
return i;
}
return -1;
}
kmp字符串匹配算法的优点:用空间换时间
kmp字符串匹配算法通过多开了一个next数组来记录前缀后缀相同情况来减少了循环次数,从而达到节省时间的优点。
(bf的时间复杂度:O(m*n) , kmp的时间复杂度:O(m+n)。)