KMP算法查找相同字符串

来源:互联网 发布:oracle创建数据库语句 编辑:程序博客网 时间:2024/06/05 16:33

问题:

  • 现在有两个字符串A和B,问你在A中是否有B,有几个??
  • 其实刚开始遇到这个问题的时候,我觉得挺简单的呀!依次循环过去查找不就可以了,当然这样做肯定能实现,而且程序编写简单粗暴,两个循环就解决了。但是这种方法的时间复杂度是O(M*N),M是字符串A的大小,N是字符串B的大小,这样时间复杂度就太高了,我们需要一个时间复杂度低的算法,这样KMP算法就孕育而生了,算法的时间复杂度为O(M+N)。

KMP算法基本原理

  • 算法的第一步就是建立一个next数组,这个数组有啥用,这个后面解释。next数组表示的是字符串B的前缀和后缀最大相等的数量,这句话什么意思??举个例子吧。
  • 假设A=“abaabaabbabaaabaabbabaab”
    • B="abaabbabaab"
  • 对于前i个数,假设i=4,这字符串“abaa”的前缀是"a",“ab”,"aba";后缀是"a","aa","aab",其中前缀和后缀相同的字符串有两组,分别是“a”所以最大相同的字符串字符数为3,故next[i-1=3]=1(数组是从0开始计数,所以这里是i-1);根据这个规律我们可以写出数组B的next={0,0,1,1,2,0,1,2,3,4,5};
  • 算法的第二步就是利用字符串B对字符串A逐步右移,在A中移动的位置用j来表示,B中移动的位置用k来表示,以上面例子来解释这个算法,当j=0,k=0时,A字符串的‘a’和B字符串的'a'两个字符相等,则j++;k++;j=1,k=1时,A字符串的‘b’和B字符串的'b'两个字符相等,继续j++,k++;依次类推到i=5,j=5时,A字符串的‘a’和B字符串的'b'两个字符不相等。这时候j=next[j-1]=2,继续将A数组的第i个字符串与B数组的第j个字符串相比较,此时A字符串的i=5为‘a’,B字符串j=2(此时j的值已经发生了改变)的值为‘a’,两个字符串相同,则i++,j++;这时候A字符串的数组为'a',B字符串的数组为‘a’,重复上述过程。最后知道i的值与A字符串长度相等的时候循环结束。这里需要注意的一点是,当比较字符与模板字符一直不相等,就比如假设上述例子i=5时遇到的字符不是'a',而是‘c’,则j=2的字符也不相等,则j=next[j-1]=0;当j=0时的字符也和‘c’不相等,如果遇到这种情况不处理的话就会出现溢出的情况,所以我们需要对其进行处理。当我们j=0时还是与第i个字符不相等时,我们就应该跳过这个字符串,即i++;在编程的时候这一点尤其要注意。
  • 介绍完该算法的整个过程,现在来分析一下它的可行性,以及为什么用产生一个next数组??这个数组有什么作用??如果你不考虑算法的层面,仅仅从数学层面上来做这道题目,我们肯定第1个字母进行比较,然后在第6个字符的时候断开了,然后你会立即从第4个字符开始进行比较,你这样做的原理是字符串A第6个字符前面两个字符与字符串B的前两个字符相同,所以我们选择第4个字符开始,这时候你再想想next数组产生的原理,有没有发现点什么??
  • 我们在第6个字符的地方断的,说明A和B前5个字符相同,next[5-1](表示第5个数)表示前缀和后缀最大相同的字符串数目,这时候是2。这说明B字符串的第1和第2的字符肯定和A数组中第4和第5个字符相等,如果这样的话我们只需要直接B数组的第三个元素与A数组的第6个元素比较就可以了。现在知道next数组的作用了吧!!!
  • 下面是我对该算法写的c代码,仅仅参考,有错误请指教:
#include"stdio.h"#include"string.h"#include"malloc.h"#define N 20//定义字符串模板长度#define N1 50//定义需要匹配的字符串的长度int *get_array(char *B);//得到next数组void main(){char B[N]="aba";//定义模板字符串char A[N1]="abaabaabbabaaabaabbabaab";//定义需要匹配的字符串int *next;//定义next数组int i=0,j=0,flag=0;next=(int *)malloc(strlen(B)*sizeof(int));//给next数组开辟空间next=get_array(B);//得到next数组的值while(i0)//防止一个字符一直找不到匹配导致溢出{j=next[j-1];}else//如果有一个字符一直找不到匹配,则进行下一个字符重新匹配{i++;j=0;}}}if(flag)//判断是否存在该模板字符串{printf("exist the number and exist number is %d ",flag);}else{printf("not exist the number");}getchar();}int *get_array(char *B){int L=strlen(B);//L代表模板字符串的长度int key=0;//用来记录前缀和后缀相同的数目int *next;//找到前缀和后缀相同的数目最大值next=(int *)malloc(L*sizeof(int));for(int i=0;imax)//判断是否最大{max=key;}}next[i]=max;//将最大数目的前缀赋值给next数组}}return next;}
原创粉丝点击