KMP算法时间代价为O(n) T
KMP算法的时间复杂度为O(m+n)
时间复杂度和这个时间代价不一样吗
m+n和n其实都是O(n)
不知道你这个问题是否已经解决, 如果还没有解决的话:首先,整个for循环中i是不断加1的,所以在整个过程中i的变化次数是O(n)级别,这个应该没有疑问。接下来考虑j的变化,我们注意到j只会在一行中增加,并且每次只加1,这样在整个过程中j最多只会增加n次;而其他地方的j都是不断减小的,由于j最小不会小于﹣1,因此在整个过程中 j 最多只能减少n次(否则j就会小于﹣1了),也就是说while循环对整个过程来说最多只会执行n次,因此j在整个过程中的变化次数是 O ( n )级别的(可以认为均摊到每次 for 循环中就是 O (1))。由于i和j在整个过程中的变化次数都是 O ( n ),因此 for 循环部分的整体时间复杂度就是 O ( n )。考虑到计算 next 数组需要 O ( m )的时间复杂度(用同样的分析方法可以得到),因此 KMP 算法总共需要O(n+m)的时间复杂度。
KMP算法的时间复杂度为O(n+m),其中n为主串的长度,m为模式串的长度。时间代价指的是程序运行的时间,与算法的时间复杂度有关但不完全等同。时间代价还受到计算机的硬件、软件等因素的影响。
KMP算法的实现步骤如下: 1. 先计算模式串的next数组,用于确定失配时模式串应该向后移动多少个字符。 2. 在主串中从左到右逐个字符匹配模式串,如果匹配不成功,则根据next数组的值将模式串向右移动,然后继续匹配,直到模式串被匹配完或主串被匹配完。 具体实现可以参考以下C++代码(以字符串为例):
#include <iostream>
#include <string>
using namespace std;
void getNext(string pattern, int next[]) {
int i = 0, j = -1;
next[0] = -1;
while (i < pattern.size()-1) {
if (j == -1 || pattern[i] == pattern[j]) {
// 如果当前字符匹配成功,则next[i+1]=j+1
i++;
j++;
next[i] = j;
}
else {
// 如果失配,则j回到next[j]的位置
j = next[j];
}
}
}
int kmpMatch(string str, string pattern) {
int i = 0, j = 0;
int next[pattern.size()];
getNext(pattern, next);
while (i < str.size() && j < pattern.size()) {
// 如果匹配成功,或者j=-1(即模式串向后移动到了起始位置),则继续比较下一个字符
if (j == -1 || str[i] == pattern[j]) {
i++;
j++;
}
else {
// 如果匹配失败,则将模式串向后移动next[j]位
j = next[j];
}
}
if (j == pattern.size()) {
// 匹配成功,返回在主串中开始匹配位置的下标
return i - j;
}
else {
// 匹配失败,返回-1
return -1;
}
}
int main() {
string str = "ababababc";
string pattern = "ababc";
int index = kmpMatch(str, pattern);
if (index != -1) {
cout << "匹配成功,起始位置为:" << index << endl;
}
else {
cout << "匹配失败" << endl;
}
return 0;
}
首先,我们先实现计算模式串的next数组的函数getNext()。在该函数中,i指向模式串尾字符的位置,j指向最长相等前后缀的前缀末尾的位置。通过while循环,从前往后遍历模式串,计算next数组的值。
然后,我们实现KMP算法的主要函数kmpMatch()。在该函数中,i指向主串当前匹配字符的位置,j指向模式串当前匹配字符的位置。首先计算出模式串的next数组。然后,我们在主串中从左到右逐个字符地匹配模式串。如果匹配成功,则i和j分别增加1。如果匹配失败,则将模式串向右移动next[j]位(即回溯到最长相等前后缀的前缀末尾的位置),继续匹配。
最后,如果匹配成功,则返回在主串中开始匹配位置的下标。如果匹配失败,则返回-1。
注:以上代码中,字符串下标从0开始,与参考资料中的代码不同。getCode()表示代码块,示例中的代码块缩进格式不正确。