kmp字符串匹配

看了一个晚上才搞懂,果然是太蒟蒻了。

kmp匹配主要是用于在一个字符串中查找一个比它小的字符串的位置,在传统的暴力算法中,时间复杂度会达到m*n,所以这时候就出现了更加快的kmp匹配算法。

和其他更快的算法相同,kmp也是一种用空间换时间的算法,通过对要查找的字符串的预处理来达到更快的效果,实际时间复杂度可以达到m+n。

讲了那么多我们应该如何来实现kmp算法呢。

首先我们得理解一个前缀子串和后缀字串的概念。

打个比方有个字符串abab

那么它的前缀子串便有 a,ab  ,  aba  

它的后缀子串  bab,ab ,b

这时他们最长的相同前缀后缀子串便是ab

我们要用kmp算法最重要的是一个next[i]数组,里面储存的就是要匹配的字符串前i项的最长相同子串大小

比如还是上面那个字符串 next[1]=0,next[2]=0,next[3]=1,next[4]=2

那这个数组有什么用呢;

比方说我们有一个字符串abacab,要在其中查找abab

这时我们匹配到c发现与要查找的不同,但是它的前3项是相同的,由kmp数组我们可以知道next[3]=1

所以abab的前一项和abacab的前三向的最后一项是相同的,我们就可以直接把abab的第一项移到abacab的前三向的最后一项进行匹配这样就可以快很多。

#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
char a[1000000], b[10000000];
int kmp[10000000];
int main() {
    cin >> a+1 >> b+1;
    int len1 = strlen(a + 1), len2 = strlen(b + 1);
    int j = 0;
    for (int i = 2; i <= len2; i++) {
        while (j && b[i] != b[j+1])j = kmp[j];
        if (b[j + 1] == b[i])j++;
        kmp[i] = j;
    }
    j = 0;
    for (int i = 1; i <= len1; i++) {
        while (j && a[i] != b[j + 1])j = kmp[j];
        if (b[j + 1] == a[i])j++;
        if (j == len2) {
            cout << i - len2 + 1 << endl;
            j = kmp[j];
        }
    }
    for (int i = 1; i <= len2; i++)
        cout << kmp[i] << " ";
    return 0;
}

 

posted @ 2021-03-17 20:59  redintonc  阅读(57)  评论(0)    收藏  举报