zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    日报 18/07/10
    meta标签
    map 和 vector 的erase函数说明
    Intel CPU MMX SSE SSE2/3/4指令集手册下载URL
    关于c中 int, float, double转换中存在的精度损失问题
    c++ 常数后缀说明
    STL中容器的push()或者push_back()函数的一点说明
    fprintf, fscanf,printf,scanf使用时参数注意
    操作系统 庞丽萍 第七章
    辨析全局变量的声明与定义
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489816.html
Copyright © 2011-2022 走看看