字符串匹配-扩展KMP(Extend-KMP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_35009437/article/details/52148288

首先还是来看看问题:
给出一个长为N的字符串S,再给出一个长为M的字符串T
求S的所有后缀中和T的最长公共前缀
显然可以想到暴力的做法,枚举S所有的后缀,然后和T做匹配,时间复杂度为O(NM)
显然,这个方法和之前的暴力一样,都处理了太多的重复操作,那么可以用类似KMP的方法来处理吗?
答案是肯定的,也就是Extend-KMP算法
可以先用类似KMP的想法,用next数组保存T[i..M1]T[0..M1]的最长公共前缀,但是有一个特例:next[0]=len
接着设p为答案伸得最远的后缀的下标,也就是T[p..M1],但是这个后缀不包括原串,
如果这两个串的公共前缀没有包括T[i],那么就要去暴力求解,如果包括就可以尝试像manacher一样用前面已经求出的答案。
接下来举个栗子:
字符串T=aaaabaaaa
那么next=9,3,2,1,0,4,???
根据之前求出的,可以知道T[0..3]=T[5..8],并且T[1..3]=T[0..2],然后把T[0..3]T[5..8]各去掉相同位置的一位,仍然相等,也就是T[1..3]=T[6..8]
根据之前的结果推导出T[6..8]=T[1..3]=T[0..2]因此,next[6]应该至少为3
然后检查是否能够增加,发现S[9]S[3] 所以next[6]不能增加,也就是3
用类似这样的方法,同样可以直接推导出extend的结果,那么就得到了答案。
以下为代码:

void get_next() {
    int len = strlen(T);
    _next[0] = len;
    int a = 0;

    while(a < len - 1 && T[a] == T[a + 1]) {
        ++a;
    }
    _next[1] = a;
    a = 1;

    for(int k = 2; k < len; ++k) {
        int p = a + _next[a] - 1;
        int L = _next[k - a];

        if(k - 1 + L >= p) {
            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;

            while(k + j < len && T[k + j] == T[j]) {
                ++j;
            }

            _next[k] = j;
            a = k;
        } else {
            _next[k] = L;
        }
    }
}

void ExtendKMP() {
    int i = 0, j, po, lenS = strlen(S), lenT = strlen(T);
    get_next();

    while(S[i] == T[i] && i < lenT && i < lenS) {
        i++;
    }

    ex[0] = i;
    po = 0;

    for(i = 1; i < lenS; i++) {
        if(_next[i - po] + i < ex[po] + po) {
            ex[i] = _next[i - po];
        } else {
            j = ex[po] + po - i;

            if(j < 0) {
                j = 0;
            }

            while(i + j < lenS && j < lenT && S[j + i] == T[j]) {
                j++;
            }

            ex[i] = j;
            po = i;
        }
    }
}

代码有点长……
最后来看看时间复杂度:
先看求next
因为内部while每运行一次,j至少加1,最多执行M次,再加上外层循环的语句,时间复杂度为O(M)
extend同理,所以总时间为O(M+N)
但是相对于KMP来说,这个算法的常数比较差,所以实际运行时应该会慢一点,但对于不是线性时间求出答案的方法,是很快的。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页