字符串模式匹配(bf+KMP)

129 阅读1分钟

给定一个主串a和一个模式串b,求模式串是否在主串中出现,若出现了返回首字母的下标,否则返回-1

该bf算法属于一个暴力思想,如果a串的长度为m,b串的长度为n,那么该算法的最坏情况下的时间复杂度为O(m*n)

一般在匹配的时候很难达到O(m*n),故还被广泛应用

程序代码:

#include<stdio.h>
#include<string.h>
char a[110],b[110];
int bf();
int main()
{
	scanf("%s%s",a,b);
	printf("%d\n",bf());
	return 0;
}
int bf()
{
	int i,j,m,n;
	m=strlen(a);
	n=strlen(b);
	i=0;
	j=0;
	while(i<m&&j<n)
	{
		if(a[i]==b[j])
		{
			i++;
			j++;
		}
		else
		{
			i=i-j+1;
			j=0;
		}
	}
	if(j==n)
		return i-j;
	return -1;
}

上面的bf算法时间复杂度是O(m*n),接下来介绍一个时间复杂度为O(m+n)的,这个算法就是KMP,说真的,我刚开始学这个算法的时候没理解,只是把它背会了,过了一段时间没用过,然后就忘了,今天我又重新看了一遍,发现之前不理解的地方现在懂了,简单的介绍一下KMP吧,该算法就是进行字符串的匹配,例如主串是T串,子串是P串,那么在进行匹配的时候我们会发现,当有一个字符匹配失败时,不需要回到最初的位置,举个例子吧,如果一个字符串是ababac,当匹配到c时失败了,其实现在不需要回到主串中的一个a的位置。仔细观察子串你会发现,ababa中前三个字符和后三个字符一样,这就意味着,当匹配到c不同时,那么c之前的aba是相同的,所以对于子串来说直接从下标为3的b开始匹配即可,而对于主串来说就是匹配失败的下标的位置,继续往后比即可。

这就牵扯到对子串的处理,需要记录下,在当前位置其最长后缀也是其前缀的长度,即是next数组。

直接来代码吧

程序代码

#include<stdio.h>
#include<string.h>
char T[10010],P[10010];
int next[10010];

void GetNext(char *str);

int main()
{
    int lenT,lenP,i,j;
    scanf("%s%s",T,P);

    GetNext(P);
    lenT=strlen(T);
    lenP=strlen(P);
    i=0;
    j=0;
    while(i<lenT)
    {
        if(j==0&&T[i]!=P[j])
            i++;
        else if(j>0&&T[i]!=P[j])
            j=next[j-1];
        else
        {
            i++;
            j++;
        }
        if(j==lenP)
            break;
    }
    if(j==lenP)
        printf("%d\n",i-lenP);
    else
        printf("-1\n");
    return 0;
}

void GetNext(char *str)
{
    int len=strlen(str);
    int i,j;
    i=1;
    j=0;
    next[0]=0;
    while(i<len)
    {
        if(j==0&&str[i]!=str[j])
        {
            next[i]=0;
            i++;
        }
        else if(j>0&&str[i]!=str[j])
            j=next[j-1];
        else
        {
            next[i]=j+1;
            i++;
            j++;
        }
    }
}