您的位置:首页 > 其它

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

2016-04-14 09:17 323 查看
在原串s中寻找模式串p的位置,如



即在位置15处找到模式串p

在比较的过程中,要充分利用模式串p中前缀后缀相同的情况,如下图





此处需要利用next[]数组,该数组用于记录前后缀相同的情况。

模式串ABCDABD
最大相同前后缀0000120
next[]-10000120
求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[]数组如下

模式串ABCDABD
next[]-1000-1020
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: