Ex-KMP(模板)

首先,明白Ex-KMP是干什么的:

给定两个字符串母串S和子串T(长度分别为n和m),下标从0开始,定义extend[i]等于S[i]…S[n-1]与T的最长公共前缀的长度,求出所有的extend[i]。

简单来说,就是求母串的每个后缀与子串的最长公共前缀长度,存在extend数组中。
即:一个母串,一个子串,多次匹配


例题链接:J - 好吃不过饺子
两个数组,a[n]和b[m],若有一个数k使得 a[k]+b[0]=a[k+1]+b[1]…=a[k+m-1]+b[m-1],求所有满足条件的k。
输入第一行为n和m,第二行为a[n],第三行为b[m]。
要求输出第一行为k的个数,第二行升序输出所有满足要求的k值。

很明显,a[k]=b[0],a[k+1]=b[1] … a[k+m-1]=b[m-1],
拿出来就是,a[k]到a[k+m-1] 等于 b[0]到b[m-1]

代码如下:

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 5;  //字符串长度最大值 
int as[maxn], bs[maxn], a[maxn], b[maxn], ans[maxn];
int n, m;
int Next[maxn], ex[maxn]; //ex数组即为extend数组  

void GETNEXT(int *str) //预处理计算next数组  
{
    int i = 0, j, po, len = m - 1;
    Next[0] = len;//初始化Next[0]  
    while (str[i] == str[i + 1] && i + 1<len)//计算Next[1]  
        i++;
    Next[1] = i;
    po = 1;//初始化po的位置  
    for (i = 2; i<len; i++)
    {
        if (Next[i - po] + i<Next[po] + po)//第一种情况,可以直接得到Next[i]的值  
            Next[i] = Next[i - po];
        else//第二种情况,要继续匹配才能得到Next[i]的值  
        {
            j = Next[po] + po - i;
            if (j<0)j = 0;//如果i>po+Next[po],则要从头开始匹配  
            while (i + j<len&&str[j] == str[j + i])//计算Next[i]  
                j++;
            Next[i] = j;
            po = i;//更新po的位置  
        }
    }
}

//计算extend数组  
void EXKMP(int *s1, int *s2)
{
    int i = 0, j, po, len = n-1, l2 = m-1;
    GETNEXT(s2);//计算子串的next数组  
    while (s1[i] == s2[i] && i<l2&&i<len)//计算ex[0]  
        i++;
    ex[0] = i;
    po = 0;//初始化po的位置  
    for (i = 1; i<len; i++)
    {
        if (Next[i - po] + i<ex[po] + po)//第一种情况,直接可以得到ex[i]的值  
            ex[i] = Next[i - po];
        else//第二种情况,要继续匹配才能得到ex[i]的值  
        {
            j = ex[po] + po - i;
            if (j<0)j = 0;//如果i>ex[po]+po则要从头开始匹配  
            while (i + j<len&&j<l2&&s1[j + i] == s2[j])//计算ex[i]  
                j++;
            ex[i] = j;
            po = i;//更新po的位置  
        }
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; i++) 
        scanf("%d", &a[i]);
    for (int i = 0; i < n - 1; i++) 
        as[i] = a[i] - a[i + 1];
    for (int i = 0; i < m; i++) 
        scanf("%d", &b[i]);
    for (int i = 0; i < m - 1; i++) 
        bs[i] = b[i + 1] - b[i];
    memset(Next, 0, sizeof(Next));
    EXKMP(as, bs);
    int cnt = 0;
    for (int i = 0; i < n - 1; i++) 
        if (ex[i] == m - 1) {
            ans[cnt++] = i;
        }
    printf("%d
", cnt);
    for (int i = 0; i < cnt; i++) 
        printf("%d ", ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/romaLzhih/p/9489816.html