KMP算法查找相同字符串
2017-09-13 21:46
176 查看
问题:
现在有两个字符串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","baa",其中前缀和后缀相同的字符串有一组,是“a”,所以最大相同的字符串字符数为1,故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 ="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;i<strlen(B);i++) { next[i]=0; //给next数组赋初值 } for(int i=0;i<L;i++) //查找前i个字符前缀和后缀的数目 { int max=0; //每次对其归0 for(int j=0;j<i;j++) //找出前i个字符的前缀和后缀 { int flag=0; //归0复位 for(int k=0;k<=j;k++) //对前i个字符的前缀和后缀依次比较进行匹配 { if(B[k]!=B[i-j+k]) //如果前缀和后缀不相同 { flag=1; //标志位,表明该前缀和后缀不相同 break; } } if(flag==0) //如果前缀和后缀相同 { key=j+1; //记录下前缀的数目 if(key>max) //判断是否最大 { max=key; } } next[i]=max; //将最大数目的前缀赋值给next数组 } } return next; }
相关文章推荐
- KMP算法字符串查找子串
- 记录一次查找字符串中多个相同字符,并设置指定大小显示
- 字符串查找KMP算法(转)
- 用递归实现查找字符串中相同字符连续出现次数的最大值
- 字符串查找KMP算法和BF算法
- 查找某些字符串在另一个字符串里相同的字符(高效)
- python算法-字符串查找KMP算法
- 查找子字符串----KMP算法深入剖析
- 查找两个字符传中最大的相同字符串
- 字符串查找以及KMP算法
- 功能:查找两个字符串有没有相同的部分
- python实现查找两个字符串中相同字符并输出的方法
- C#:比较二个字符串,查找出相同字数和差异字符
- 查找两个字符串中的相同的字符位置
- 字符串查找算法之(一)KMP算法
- 查找在一个字符串中含有多少个相同的子字符串
- 字符串查找(2)KMP算法
- 查找字符串里面有没有相同的字符- -
- 子字符串的查找/KMP算法(正在更新)
- 查找一个字符串数组中两个或两个以上的相同字符串(swfit,oc)