hiho一下第3周#1015 : KMP算法

来源:互联网 发布:淘宝免费注册账号申请 编辑:程序博客网 时间:2024/05/17 06:28

在原串s中寻找模式串p的位置,如
这里写图片描述
即在位置15处找到模式串p

  • 在比较的过程中,要充分利用模式串p中前缀后缀相同的情况,如下图
    这里写图片描述
    这里写图片描述
    此处需要利用next[]数组,该数组用于记录前后缀相同的情况。
模式串 A B C D A B D 最大相同前后缀 0 0 0 0 1 2 0 next[] -1 0 0 0 0 1 2 0


  • 求next[]数组,假如已知next[0,…,j],如何求next[j+1],这里next[j]=k,如下图
    这里写图片描述

1、若p[k] == p[j],则next[j+1] = k+1(next[]数组是最大前后缀长度表右移的结果)
2、若p[k] != p[j],则k = next[k],再去比较p[next[k]]与p[j]是否相等

经过上述过程可以得到最长相同前后缀右移的netxt[]数组,考虑以下情况
这里写图片描述
此时若将数组移动到p[1]处,显然s[9]=’C’与p[1]=’B’不同,原因是p[k]==p[j]时,若p[k+1]=p[j+1],此时将next[]数组再一次递归得到next[j]=next[k],代码如下

class myKMP {public:    int next[1000002] = {};     //全部赋值为0    string p;public:    myKMP(string &s) {          //初始化next[]数组        p = s;        int len = p.size(), k = -1, j = 0;        next[0] = -1;        while (j < len) {   //末尾添加一位(针对此题的修改)            if (k == -1 || p[j] == p[k]) {  //比较前后缀                ++j; ++k;                if (p[j] != p[k]) {                    next[j] = k;                } else {                    next[j] = next[k];                }            } else {                k = next[k];            }        }    }    int search(string &s) {        int i = 0, j = 0, ans = 0;        int slen = s.size(), plen = p.size();        while (i < slen) {            if (j == -1 || s[i] == p[j]) {                ++i; ++j;            } else {                j = next[j];            }            if (j == plen)  ans++;  //此时已经可以结束                                //此处为针对此题的修改        }        return ans;    }};

查找的过程只需要跟着next[]数组跳转就好,优化后的next[]数组如下

模式串 A B C D A B D next[] -1 0 0 0 -1 0 2 0
0 0