KMP 알고리즘 - KMP를 얻기 위해 여섯 단계
1. 무엇 KMP입니다
KMP 알고리즘은 KMP 템플릿 매칭 알고리즘이라고 누스-Morria-프랫 알고리즘이라고 DEKnuth, J, H, 모리스 협찬 VRPratt 세 족장이다. 존경 브 루트 포스 (폭력) 알고리즘이 알고리즘은 상대적으로 큰 개선을 중심으로 시간의 효율성을 향상시킬 수있는 주요 문자열 포인터 등을 제거있다. (시간위한 공간)
2.KMP 간단한 템플릿 매칭 (전수)
폭력 브 루트 포스
이 비교를 통해 슈퍼 간단한 스테핑입니다. . . .
문자열을 감안할 때 S, T , T 에 S 한 최초의 길이 T 비교 문자열로는, 성공적으로 첫 번째 인덱스 매칭 반환 경기 계속 실패 S를 다음의 길이 T 같은 단어 문자열 ......의 각각의 반복을 통해 길이 T 동일한 문자열과 일치하는 이 시간 복잡성 (N * m) O이다.
KMP 템플릿 매칭 알고리즘 - CAN 구현 복잡도 O (m + n)의
첫 번째 단계는 : 접두사와 접미사 어떤 문자열 이해하기
: 같은
ABC해야합니다 - abcjkdabc, 배열과 같은 가장 긴 접미사의 다음 가장 긴 접두사.
cbcbc, 같은 긴 접두사와 접미사 긴 -이다 CBC.
abcbc, 접두사와 접미사 동일한 최대의 긴, 그것은 존재하지 않습니다.
긴 접두사를 참고 : 첫 번째 문자는 시작했다,하지만 마지막 문자가 포함되어 있지 않습니다.
第二步,理解关于字符串匹配的规则
假设S与T要进行匹配,匹配规则如图
这里aba就是最长前缀字串,然后下一次a是最长前缀字串
借别人的图示意:
第三步,如何得出j的更新规则——即计算next数组
我看了数据结构(java)第四版,讲的很好。
公式:
例子演示:
第四步,上计算next数组的代码
int get_next(string t,int * next) {
//先定义一个数组
int length = t.length();
int j=0,k=-1;
next[0] = -1;
while(j<length-1)//因为我们是在找最长前缀字串,这里得减一。
if(k==-1||t[j]==t[k]) { //当前的字串最新的字符相等或者字串总长度1
k++;
j++;//比较下一个字符
next[j] = k;//最长前缀字串记录下来,因为前面的k,j都加了1
} else
k = next[k];//重新在k长度的前缀字串找当前j长度字串的最长前缀字串,更新索,听说这里是最难理解的
return 1;
}
第五步,理解 k = next[k]
k = next[k];//重新在k长度的前缀字串找当前j长度字串的最长前缀字串,
这里我给例子演示,反正我是一下子就理解了。
图示:因为p5!=p11,这个时候,最长前缀字串肯定不会比上次的大了,不可能是6,我们只能重新寻找,而重新寻找的规则就是k = next[k]=2
第六步,最后一步,上匹配字串的代码
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
//建立next数组
int get_next(string t,int * next) {
//先定义一个数组
int length = t.length();
int j=0,k=-1;
next[0] = -1;//这里是为了
while(j<length-1)//因为我们是在找最长前缀字串,这里得减一。
if(k==-1||t[j]==t[k]) { //当前的字串最新的字符相等或者字串总长度1
k++;
j++;//比较下一个字符
next[j] = k;//最长前缀字串记录下来
} else
k = next[k];//重新在k长度的前缀字串找当前j长度字串的最长前缀字串,更新索
return 1;
}
int compare_str(string s,string t,int pos) {
int n=s.length();
int m = t.length();
if(n<m||pos>=n||n==0) { //不合理的输入
return 0;
}
if(pos<=0) {
pos=0;//提高容错率
}
int next[m];
//生成next数组
get_next(t,next);
int i=pos,j=0;
while(i<n&&j<m)
if(j==-1||s[i]==t[j]) { //当前匹配成功,继续匹配下一个字符
i++;
j++;
} else { //i是不回溯,匹配规则更新匹配的j
j = next[j];//这里就是我们说的匹配规则
if(n-i+1<m-j+1)//剩下的字串不够t的长度,就不用比较了
break;
}
if(j==m)
return i-j;//成功匹配。,返回对应的索引
return -1;//否则退出
}
int main() {
string t,s;
cin>>s;
cin>>t;
int pos =compare_str(s,t,0);
cout<<pos;
return 0;
}
更新改进KMP算法。
现在我们比较的是C和B,不匹配。
显然,当我们上边的算法得到的next数组应该是[ -1,0,0,1 ]
所以next[3] = 1。下一步的匹配:明显我们又来比较C和B,这是是多余的
所以我们应该改进计算next数组匹配
改进的算法 就是避免这种情况,代码演示
int get_next(string t,int * next) {
//先定义一个数组
int length = t.length();
int j=0,k=-1;
next[0] = -1;
while(j<length-1)//因为我们是在找最长前缀字串,这里得减一。
if(k==-1||t[j]==t[k]) { //当前的字串最新的字符相等或者字串总长度1
k++;
j++;//比较下一个字符
//使用改进的算法
if(t[j]!=t[k])
next[j] = k;//最长前缀字串记录下来
else next[j] = next[k];//直接跳到上次找到的后缀字串,改进的代码结束
} else
k = next[k];//重新在next[k]长度的前缀字串找当前j长度字串的最长前缀字串,更新索引
return 1;
}
참고 블로그
https://blog.csdn.net/dark_cy/article/details/88698736 :
https://blog.csdn.net/starstar1992/article/details/54913261?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source= distribute.pc_relevant.none-작업