数据结构KMP的时间复杂度

KMP算法时间代价为O(n) T
KMP算法的时间复杂度为O(m+n)
时间复杂度和这个时间代价不一样吗

m+n和n其实都是O(n)

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这篇博客: KMP算法 思路+模板代码中的 时间复杂度分析:O(n+m) 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    首先,整个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)的时间复杂度。


  • 以下回答来自chatgpt:

    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()表示代码块,示例中的代码块缩进格式不正确。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^