KMP算法查找相同字符串

问题:

现在有两个字符串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[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;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算法
    原文地址: https://blog.csdn.net/hxlove123456/article/details/77971536
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞