题目

模式串可以浮动的模式匹配问题 给出模式串的相对大小,需要找出模式串匹配次数和位置 比如说模式串:1,4,4,2,3,1 而主串:5,6,2,10,10,7,3,2,9 那么2,10,10,7,3,2就是匹配的

首先是kmp的next数组求法

void_getnext(char x[], int m, int next[])
{
    int i, j;
    i = 0;
    j = next[0] = -1;
    while(i < m)
    {
        while(j != -1 && x[i] != x[j]) j = next[j];
        next[++i] = ++j;
    }
}

预处理每一位之前的每一种字符出现的次数。前缀和(还可以树状数组维护)

void init()
{
    for(int i=0;i<n;i++)
    {
        if(i==0)
        {
            for(int j=1;j<=25;j++)
                as[i][j]=0;
        }
        else
        {
            for(int j=1;j<=25;j++)
                as[i][j]=as[i-1][j];
        }
        as[i][a[i]]++;
    }
    for(int i=0;i<m;i++)
    {
        if(i==0)
        {
            for(int j=1;j<=25;j++)
                bs[i][j]=0;
        }
        else
        {
            for(int j=1;j<=25;j++)
                bs[i][j]=bs[i-1][j];
        }
        bs[i][b[i]]++;
    }
}

接下来求kmp中的next数组(需要求出j-i中比b[i]小的数的个数和与b[i]相同的数的个数 和 j之前比b[j]小的数的个数和与b[j]相同的数的个数 kmp基础思想)

void kmp_pre()           //处理出Next数组
{
    int i,j;
    j=Next[0]=-1;
    i=0;
    while(i<m)
    {
        int t11=0,t12=0,t21=0,t22=0;
        for(int k=1;k<b[i];k++)        // t11  从i往前j个牛有多少个比bi小的
        {
            if(i-j>0)
                t11+=bs[i][k]-bs[i-j-1][k];
            else
                t11+=bs[i][k];
        }
        if(i-j>0)                    // t22  从i往前j个牛,有多少个和bi一样的
            t12=bs[i][b[i]]-bs[i-j-1][b[i]];
        else
            t12=bs[i][b[i]];
        for(int k=1;k<b[j];k++)       //t21   第j头牛之前有多少个比bj小的
        {
            t21+=bs[j][k];
        }
        t22=bs[j][b[j]];               //t22   第j头牛之前有多少个和bj一样的
        if(j==-1 || (t11==t21 && t12==t22))    //转化为正常kmp思路
        {
            Next[++i]=++j;
        }
        else
            j=Next[j];
    }
}

接下来就是激动人心的匹配时间
正常的匹配代码:

int KMP_count(char x[], int m, char y[], int n)
{
    //预处理出char x[] 的next数组 preKMP(x,m,next);
    int i,j;  
    int ans = 0;     
    i = j = 0;
    //开始匹配
    while(i < n)
    {
        while(j != -1 && y[i] != x[j]) j = next[j];
        i++, j++;
        if(j >= m)
        {
            ans ++;
            j = mext[j];
        }
    }
    return ans;
}

这道题的kmp

void kmp()
{
    ans.clear();
    int i,j;
    kmp_pre();
    i=j=0;
    while(i<n)
    {
        //和kmppre一样的处理方法,计算小于本rank的和等于本rank的
        int t11=0,t12=0,t21=0,t22=0;
        for(int k=1;k<a[i];k++)
        {
            if(i-j>0)
                t11+=as[i][k]-as[i-j-1][k];
            else
                t11+=as[i][k];
        }
        if(i>j)
            t12=as[i][a[i]]-as[i-j-1][a[i]];
        else
            t12=as[i][a[i]];
        for(int k=1;k<b[j];k++)
        {
            t21+=bs[j][k];
        }
        t22=bs[j][b[j]];
        if(j==-1 || (t11==t21 && t12==t22))
        {
            i++;
            j++;
            if(j>=m)
            {
                ans.push_back(i-m+1);
                j=Next[j];
            }
        }
        else
            j=Next[j];
    }
}

然后本题就做完啦!