KMP(模板)

1.KMP算法

KMP算法是用来处理一对一的匹配的。

朴素的匹配算法,或者说暴力匹配法,就是将两个字符串从头比到尾,若是有一个不同,那么从下一位再开始比。这样太慢了。所以KMP算法的思想是,对匹配串本身先做一个处理,得到一个next数组。这个数组是做什么用的呢?next [j] = k,代表j之前的字符串中有最大长度为k 的相同前缀后缀。记录这个有什么用呢?对于ABCDABC这个串,如果我们匹配ABCDABTBCDABC这个长串,当匹配到第7个字符T的时候就不匹配了,我们就不用直接移到B开始再比一次,而是直接移到第5位来比较,岂不美哉?所以求出了next数组,KMP就完成了一大半。next数组也可以说是开始比较的位数。

计算next数组的方法是对于长度为n的匹配串,从0到n-1位依次求出前缀后缀最大匹配长度。

比如ABCDABD这个串:

《KMP(模板)》

(图片来源https://www.cnblogs.com/zhangtianq/p/5839909.html)

如何去求next数组呢?k是匹配下标。这里没有从最后一位开始和第一位开始分别比较前缀后缀,而是利用了next[i-1]的结果。

如何去求next数组呢?k是匹配下标。这里没有从最后一位开始和第一位开始分别比较前缀后缀,而是利用了next[i-1]的结果。

void getnext()//获取next数组
{
    int i,n,k;
    n=strlen(ptr);
    memset(next,0,sizeof(next));
    k=0;
    for(i=1;i<n;i++)
    {
        while(k>0 && ptr[k]!=ptr[i])
            k=next[k];
        if(ptr[k]==ptr[i]) k++;
        next[i+1]=k;
	//next表示的是匹配长度
    }
}

 

这里我是按照《算法导论》的代码来写的。算法导论算法循环是从1到n而不是从0到n-1,所以在下面匹配的时候需要j=next[j+1]。

int kmp(char *a,char *b)//匹配ab两串,a为父串
{
    int i=0,j=0;
    int len1=strlen(a);
    int len2=strlen(b);
    getnext();
    while(i<len1&&j<len2)
    {
        if(j==0||a[i]==b[j])
        {   i++;j++;       }
        else j=next[j+1];//到前一个匹配点
    }
    if(j>=len2)
        return i-j;
    else return -1;
}

 


 

这里next数组的作用就显现出来了。最后返回的是i-j,也就是说,是从i位置前面的第j位开始的,也就是上面说的,next数组也可以说是开始比较的位数。也就是说,在父串的i位比的时候已经是在比子串的第j位了。

一个完整的代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=100;
char str[100],ptr[100];//父串str和子串ptr
int next[100];
string ans;
void getnext()//获取next数组
{
    int i,n,k;
    n=strlen(ptr);
    memset(next,0,sizeof(next));
    k=0;
    for(i=1;i<n;i++)
    {
        while(k>0 && ptr[k]!=ptr[i])
            k=next[k];
        if(ptr[k]==ptr[i]) k++;
        next[i+1]=k;
	//next表示的是匹配长度
    }
}
int kmp(char *a,char *b)//匹配ab两串,a为父串
{
    int i=0,j=0;
    int len1=strlen(a);
    int len2=strlen(b);
    getnext();
    while(i<len1&&j<len2)
    {
        if(j==0||a[i]==b[j])
        {  
            i++;
            j++; 
        }
        else j=next[j+1];//到前一个匹配点
    }
    if(j>=len2)
    return i-j;
    else return -1;
}
int main(){
	while( scanf( "%s%s", str, ptr ) )
	{
        int ans = kmp(str,ptr);
        if(ans>=0)
            printf( "%d\n", kmp( str,ptr ));
        else
            printf("Not find\n");
	}
	return 0;
}
转载:https://blog.csdn.net/qq_30346729/article/details/78835040

 

 

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/FACEYc/article/details/81772256
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞