KMP算法概括

KMP算法有很多不错的解析,这里推荐两个:12

本文只是做一个简单的概括。

思想

KMP算法的思想用下面一张图就能说清楚:

在上图中,要检测T中是否包含P。

当匹配到某个位置发现两者不相等时(红框),肯定P要继续往后挪。普通的字符串匹配方法(也就是时间复杂度时m*n的那种),一般P只往后挪一个位置(也就是P'),然后从头开始和T比较。但是如图所示,当我们发现红框位置的不一样时,同时也代表P中红框前5个字母已经和T匹配上了,所以只有图中蓝色框部分的字母相同时,P'的比较才有意义,否则P'在前4个字母的比较时候就会匹配失败。

换句话说,当红框位置的匹配失败时,只有b之前的字母有相同的前后缀时,后移后的比较才有意义。再看下图

还是同一个字符串,其中b之前还真有相同的前后缀,也就是“ab”。此时我们可以断言,把P后挪3个位置时安全的,起码对于T中我们已经“看”过的字母,P和它匹配还好。

所以KMP算法的关键就是构建Failure Array(很多博客叫next数组)。next数组的长度和P长度相同,next[j]代表的含义是,在P[:j+1]中,最长的相同的前后缀长度是多少,如下图。next中的2表示P中截止到第5个字母为止的字串中,最长的前后缀是2。(注意,在具体实现时,有的人next的位置和我描述的刚好差1,如上面给的第2个参考文档中的实现)

LeetCode第28题就是实现字符串匹配,代码如下:

class Solution {
public:
    vector<int> generate_next(string s){
        int i = 0, j = 1;
        vector<int> res(s.size(), 0);
        while(j < s.size()){
            if(s[i] == s[j]){
                res[j++] = ++i;
            } else if(i > 0){
                i = res[i-1];
            } else{
                res[j++] = 0;
            }
        }
        return res;
    }
    
    int strStr(string haystack, string needle) {
        vector<int> next = generate_next(needle);
        int i = 0, j = 0;
        while(j < needle.size() && i < haystack.size()){
            if(haystack[i] == needle[j]){
                ++i, ++j;
            } else if(j > 0){
                j = next[j-1];
            } else {
                ++i;
            }
        }
        if(j == needle.size()){
            return i - needle.size();
        } else{
            return -1;
        }
    }
};

假如P的长度是m,T的长度是n,KMP算法的时间复杂度是O(m+n),其中构建next数组复杂度是O(m),匹配复杂度是O(n)。有一个很有趣的证明,以上述的代码为例:

  1. 构建next时,考虑2*j - i的大小,会发现它初始是0,最终最大是2m,且三个if-else分支不论走哪个,2*j-i都是递增的,所以最多训练2m次,也就是O(m).
  2. 匹配时也同理,考虑2*i-j的大小,可以得到同样的结论。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 字符串匹配KMP算法详解 1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有...
    张晨辉Allen阅读 2,430评论 0 3
  • 引言 字符串匹配一直是计算机科学领域研究和应用的热门领域,算法的改进研究一直是一个十分困难的课题。作为字符串匹配中...
    潮汐行者阅读 1,672评论 2 6
  • 数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章、这篇文章、还有这篇他们写得非常...
    sunhaiyu阅读 1,755评论 1 21
  • 数据结构 第8讲 KMP算法 讲这个算法之前,我们首先了解几个概念: 串:又称字符串,是由零个或多个字符组成的有限...
    rainchxy阅读 1,340评论 0 3
  • 引言   串或字符串,属于线性结构,自然的可以利用向量(Vector)或者链表(List)等序列结构加以实现,通常...
    YAFree阅读 2,282评论 1 1