KMP,扩展KMP和最小表示法都是那种朴素是O(m*n)的优化成O(m+n),而且基本思想都是利用前面已经得到的结果来优化后面的步骤,也就是每当失配时指针会大幅度移动,这样最后达到线性的复杂度。
以S为主串,T为模式串来举例(即用T去匹配S),A表示T匹配T得到的数组,B表示T匹配S得到的数组,然后KMP就是
int j=0;
for(int i=0;i=0;i0&&(T[j+1]!=S[i]))j=A[j];
if(T[j+1]==S[i])
j++;
B[i]=j;
if(j==m-1){
printf("find!\n");
j=A[j];
}
}
这是说如果失配,主串不动,模式串移动到合适位置,而最后B[i]得到的就是S串中以i结尾的能匹配模式串的长度,同理A的求法就是自己匹配自己。
再来看看扩展KMP
j=0;
while(j
这里的B[i]得到的则是S串中以i开头的能匹配模式串的长度,综合一下,就是说KMP得到的是S[i-B[i]+1]..S[i]=T[0]..T[B[i]-1],而扩展KMP则是说S[i]..S[i+B[i]-1]=T[0]..T[B[i]-1],这样差别就比较明显了,然后就是每次求后面的都是利用了之前求出的内容来推出后面的,具体还是不明白的话可以查看matrix67大牛的KMP讲解和我以前写的扩展KMP的内容,还有就是KMP只是单模式串匹配如果多模式串匹配那就是Aho_Corasick自动机了,其实思想还是KMP的思想,一开始的那张图就是Aho_Corasick自动机构造好图的样式了。
然后就是说一下最小表示法又称作最小环排列,是说把一个字符串看成一个环,有n种线性表示(就是说把环切开) ,这里面最小的就是最小环排列,代码
int MCP(){
int i = 0, j = 1, count = 0, t,len=n;
while (i < len && j < len && count < len){
tt++;
int x = i + count;
int y = j + count;
if (x >= len) x -= len;
if (y >= len) y -= len;
if (s[x] == s[y])
count++;
else{
if (s[x] > s[y])
i = i + count + 1;
else
j = j + count + 1;
count = 0;
}
if(j==i)
j=i+1;
}
return i;
}
算法很奇妙,只要失配便大幅度移动指针。正确性需要仔细考虑一下,注意到最小的首字母肯定是最小的,这样后面的也就好想了。
这几个算法如果想明白了,理解还是不难的,而且触类旁通,比如最小回文子串的问题同样可以利用这种用以前的推以后的思想然后得出线性的算法。最后这里有个各种字符串算法的大总结,有兴趣的可以看看。
恩 理解了一下又
@丕子:
test
连到网易的连接有问题啊……
@orbbyrp: 没有问题啊,只不过有时很慢而已。。。
好像是我这里的问题……
@orbbyrp: 囧,回复的好快!!!
第一个KMP算法的程序里这句话“2.for(int i=0;i=0;i<n){”有问题吧?是不是应该是
“2.for(int i=0;i<n;i++){”?
@IGNORE: 是啊,手抖写错了。。。
strlen一次是On的吧。
@Sigma: 似乎是啊_(:3 」∠)_还是应该拿出来,编译器可能给优化了一直没注意
@isnowfy:
理論上是O(N)沒錯,不過實做上cstring有15個char並不會比較16次,比較有可能是4+4次的比較與其他少許的位元計算開銷。不過這個算法只針對字元大小是 1 Byte 的 cstring http://www.spongeliu.com/421.html