KMP算法

64 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

以图中的例子来说,在 i 处失配,那么主字符串和模式字符串的前边6位就是相同的。又因为模式字符串的前6位,它的前4位前缀和后4位后缀是相同的,所以我们推知主字符串i之前的4位和模式字符串开头的4位是相同的。就是图中的灰色部分。那这部分就不用再比较了。 s[ ]是模式串,即比较长的字符串

#include <iostream>

using namespace std;

const int N = 100010,M = 1000010;

int n,m;
char p[N],s[M]; // p是要匹配的字符串
int ne[N];

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> p+1 >> m >> s+1;


    // 求next数组
    for(int i = 2,j = 0; i <= n; i++)
    {
        while(j && p[i] != p[j+1]) j = ne[j];
        if(p[i] == p[j+1]) j++;
        ne[i] = j;
    }

    // kmp匹配过程
    for(int i = 1,j = 0; i <= m; i++)
    {
        while(j && s[i] != p[j+1]) j = ne[j];
        if(s[i] == p[j+1]) j++;
        if(j == n)
        {
            // 匹配成功
            cout << i - n << ' ';
            j = ne[j];
        }
    }
    return 0;
}
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

void prefix_table(char pattern[], int prefix[], int n)
{
    prefix[0] = 0;
    int len = 0;
    int i = 1;
    while(i < n)
    {
        if(pattern[i]==pattern[len])
        {
            len++;
            prefix[i] = len;
            i++;
        }
        else
        {
            if(len > 0)
            {
                len = prefix[len - 1];
            }
            else
            {
                prefix[i] = 0;
                i++;
            }
        }
    }
}

void prefix_move(int prefix[], int n)
{
    for(int i = n - 1; i > 0; i--)
    {
        prefix[i] = prefix[i-1];
    }
    prefix[0] = -1;
}

void kmp_search(char text[], char pattern[])
{
    int n = strlen(pattern);
    int m = strlen(text);
    int *prefix = (int *)malloc(sizeof(int) * n);
    prefix_table(pattern, prefix, n);
    prefix_move(prefix,n);
    int i = 0, j = 0;
    while(i < m)
    {
        if(j == n-1 && text[i] == pattern[j])
        {
            printf("%d\n",i-j+1);
            j = prefix[j];
        }
        if(text[i]==pattern[j]) i++, j++;
        else
        {
            j = prefix[j];
            if(j == -1) i++, j++;
        }
    }
    prefix_table(pattern, prefix, n);
    for(i = 0; i < n; i++)
    {
        printf("%d ",prefix[i]);
    }
    //text[i] , len[text] = m
    //pattern[j] , len[pattern] = n
}
 int main()
 {
     char text[1000010];
     char pattern[1000010]; //要搜索的内容
     cin >> text;
     cin >> pattern;
     kmp_search(text, pattern);


     return 0;
 }