简述:该算法是在一个主字符串里找到另一个字符串的非暴力破解算法。
字符串s:abcabcabcd 模式t: abcabcd
暴力破解BF(Brute-Force)算法:每一次都将字符串t沿主字符串一位一位向右硬推,一旦发现有字符对应不同,则将第一个比较位右移一位重新比较。算法复杂度是(m * n), m、n分别是两个字符串的长度。
Kmp算法:该算法记录了模式t中,的最长前缀,通过这个记录,可以在失配的时候,跳过一些已知的明显不用比较的字符,进行下一步比较。在上面这个例子中我们令两个字符串: char *s = “abcabcabcd” ; char *t = “abcabcd”
当依次比较到s[6] = ‘a’ 然而t[6] = ‘d’ 时,发现两个字符串失配了,如果在暴力破解算法中,那么就是s[1] = ‘b’ 和 t[0] = ‘a’ 开始第二轮比较;但是在kmp算法中, 我们要做的是把
S[6] = ‘a’ 和 t[3]=’a’ 接下去进行比较就可以了 这样就省去了BF算法中 { s[1]&t[0]}、 { s[2]&t[0] } 、{s[3]&t[0] 、{s[4]&t[1]} 、{s[5]&t[2]} , 直接比较s[6]&t[3] ,进而继续比较下去。一旦与主字符串某个字符位失配后,从模式t的第几个字符继续开始匹配的函数就是实效函数next[i] ,其中i表示模式t的第i个位置的字符。
关键点: 其实就是找模式t的i位置之前最长的对称字符前缀
如“abcabcd” 则在’d’字符前的最长前缀是abc所以一旦在’d’位置发生失配, 那就直接去找第四个’a’,再继续匹配。
又如char *t = “abcdabce”如果在’e’处发生失配,那么看e前面的那些字符串,最大对称(可重复)”abc” 长度是3那么接下来由next函数得到的失配后的字符比较位置是t[3] = ‘d’
下面来列举一个可重复的前缀情况 char*t = “abcabcabcd”,如果在’d’出发生失配,那么next函数在t[9] = ‘d’ 出的next失效函数, 通过计算next[9 - 1] = 6 ,之后将t[9] 和 s[startPosition + 6]进行比较
后面是参考网上代码写成的:
在主字符串s 查找字符串t 的位置
#include <iostream> using namespace std; //在主字符串s里找到字符串t的位置 int KMP_find(const char *s, const char *t){ /********************求失效函数***********************/ int lenT = strlen(t); int *next = new int[lenT]; next[0] = -1; for (int i = 1;i < lenT;i++){ int u = next[i - 1]; while(t[i] != t[u + 1] && u >= 0) u = next[u]; if(t[i] == t[u + 1]) next[i] = u + 1; else next[i] = -1; } /*****************************************************/ int lenS = strlen(s); int i = 0,j = 0; while(i < lenS && j < lenT){ if(t[j] == s[i]){ i++; j++; } else if (j == 0) i++; //如果t的第0位都无法匹配,那只好主字符串向右移一位 else j = next[j - 1] + 1; } delete next; if(j < lenT) return -1; //匹配失效 else return i-j; } int main(){ char *s = "abcabcabcd"; char *t = "abcabcd"; cout << KMP_find(s,t); }