扩展KMP

扩展KMP可以快速求出T与S每个后缀的LCP,时间复杂度和空间复杂度都比后缀数组要优良很多。

const LL N = 200005;
//扩展KMP
int nex[N];//T串的每一个后缀与T的LCP
int ext[N];
char S[N];
char T[N];
void getNex()
{
    //int len = T.length();
    int len = strlen(T);
    nex[0] = len;
    int i=0, j=0,po=1;
    while (i + 1 < len&&T[i] == T[i + 1])i++;
    nex[1] = i;
    for (i = 2; i < len; i++)
    {
        int P = nex[po] + po;
        if (i + nex[i - po] < P)//(T均为T的后缀)因为T[po]和T[0]匹配,所以T[i]和T[i-po]匹配,那么只要知道nex[i-po],计算最远长度是否超过P
            nex[i] = nex[i - po];
        else
        {
            j = P - i;//nex[i-po]>P-i,所以从P-i往后都是未知的,需要匹配.
            if (j < 0)j = 0;//如果po也没有lcp就会出现负数,就0开始匹配
            while (i + j<len&&T[i + j] == T[j])j++;
            nex[i] = j;
            po = i;//这里if可以不需要,因为如果P不够匹配了,新的j必然>=P
        }
    }
}
void exKmp()
{
    getNex();
    //int lens = S.length();
    //int lent = T.length();
    int lens = strlen(S);
    int lent = strlen(T);
    int i=0, j=0, po=0;
    while (i+j<lens&&j<lent&&S[i + j] == T[j])j++;
    ext[i] = j;
    po = 0;
    for (i = 1; i < lent; i++)
    {
        int P = ext[po] + po;
        if (i + nex[i - po] < P) ext[i] = nex[i - po];//此处用nex而不是ext的原因是,需要通过T串后缀的lcp找到尽可能匹配的长度
        else
        {
            j = P - i;
            if (j < 0)j = 0;
            while (i + j<lens&&j<lent&&S[i + j] == T[j])j++;
            ext[i] = j;
            po = j;
        }
    }
}

 

posted @ 2017-10-02 16:43  Luke_Ye  阅读(261)  评论(0编辑  收藏  举报