在对KMP算法的时间复杂度进行计算的时候,发现阮一峰的博客中对KMP算法的核心——next数组的解释和使用时与《大话数据结构》的作者程杰有很大差别:
例如ABCDABD,得到的next数组为[0,0,0,0,1,2,0]。简单地观察一下就会发现,该算法会进行最少21次的字符串判断,这还是在不考虑字符串匹配的时间消耗。光此一项的时间复杂度就是
O(n) = (n(n - 1)) /2 = n² / 2 + n / 2 = n²。
在加上匹配字符串,就是m + n²显然大于KMP算法的时间复杂度m + n。
function get_next(s) {
var i = 1;
var j = 0;
var next = [0];
while (i < s.length) {
if (j == 0 || s.charAt(i - 1) == s.charAt(j - 1)) {
i++;
j++;
next.push(j);
} else {
j = next[j - 1];
}
}
return next;
}
例如:
- j=0, i=1, (j=0), next=[0,1];
- j=1, i=2, (A!=B), j=next[0];
- j=0, i=2, (j=0), next=[0,1,1];
- j=1, i=3, (A!=C), j=next[0];
- j=0, i=3, (j=0), next=[0,1,1,1];
- j=1, i=4, (A!=D), j=next[0];
- j=0, i=4, (j=0), next=[0,1,1,1,1];
- j=1, i=5, (A=A), next=[0,1,1,1,1,2];
- j=2, i=6, (B=B), next=[0,1,1,1,1,2,3];
总共运行9次就获得了next数组,算法时间复杂度是O(n) = n。
//1.阮
//i值即移动位数:移动位数 = 已匹配的字符数 - 对应的部分匹配值
function kmp(s1, s2) {
var next = getNext(s2);
var j = 0;
for (var i = 0; i < s1.length;) {
for (; j < s2.length; j++) {
if (s1.charAt(i + j) != s2.charAt(j)) {
i += j > 0 ? (j - next[j - 1]) : 1;
j = next[j > 0 ? j - 1 : 0];
break;
} else if (j == s2.length - 1) {
return i;
}
}
}
return -1;
}
//2.程
function kmp2(s1, s2) {
var j = 0;
var next = get_next(s2);
for (var i = 0; i < s1.length;) {
for (; j < s2.length; j++) {
if (s1.charAt(i) != s2.charAt(j)) {
j == 0 ? i++ : true;
j = next[j > 0 ? j - 1 : 0];
break;
} else if (j == s2.length - 1) {
return i - j;
}
i++;
}
}
return -1;
}
//3.也正是由于i值的大小随着j值的大小进行改变,
// 使得被查找字符串仅被遍历一次即可得到解。
// 故时间复杂度为m
// 加上获得next数组的时间复杂度就是kmp算法的总时间复杂度m+n;