KMP算法详解


在数据结构课上老师讲了kmp算法,但当时并没太懂,现在把思路重新理一遍。

1.kmp算法简介

KMP是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt同时发现的。
KMP算法其实就是一种改进的字符串匹配算法,关键是利用匹配后失败的信息,尽量减少模式串(W)与主串(T)的匹配次数以达到快速匹配的目的。具体实现就是实现一个next() 函数,函数本身包含了模式串的局部匹配信息。时间复杂度 O(m+n)
如果考虑最笨的方法,我们可以将T[0]和W[0]进行匹配,如果相同则匹配下一个字符,直到出现不相同的情况,此时我们会丢弃前面的匹配信息,然后把T[1]跟W[0]匹配,循环进行,直到主串结束,或者出现匹配成功的情况。这种丢弃前面的匹配信息的方法,时间复杂度为O(mn)
KMP算法利用已经部分匹配这个有效信息,保持i指针(主串)不回溯,通过修改j指针,让模式串尽量地移动到有效的位置,具体可见下面一个例子。
如果主串为:a b c a b c d h i j k
模式串为:a b c e
当我们匹配到主串的第四个字符a时,可知a和e不相等,因此需要移向下一位,但其实我们并不需要从模式串中的第一位重新开始比较,因为主串中的前三个字符已经没有未匹配的a了,不可能匹配成功。
[站外图片上传中...(image-f5d3d1-1518266644982)]

2.next()函数

因此,最关键的是找到如何移动j指针。我们记当匹配失败时,j要移动的下一个位置为k(即next[j]= k)。记P为模式串。
很显然,存在这样一个性质:最前面的k个位置(对于模式串来说)和j之前的最后k个字符(主串)是一样的。因此得到公式:

P[0 ~ k-1] == P[j-k ~ j-1]

当P[k] == p[j]时

有P[0 ~ k-1] + P[k] == p[j-k ~ j-1] + P[j],即:P[0 ~ k] == P[j-k ~ j],因此可得

next[j+1] == k + 1 == next[j] + 1

当P[k] != p[j]时

我们只能在0~k-1中去寻找最长后缀串了,因此为

k = next[k]

使用C++ 实现next函数为

    int* getNext(string p)
    {
        int* next = new int[p.length()];
        next[0] = -1;           //while the first char not match, i++,j++
        int j = 0;
        int k = -1;
        while (j < (int)p.length() - 1)
        {
            if (k == -1 || p[j] == p[k])
            {
                j++;
                k++;
                next[j] = k;
            }
            else
            {
                k = next[k];
            }
        }
        return next;
    }

3.完整算法

    int KMP(string T,string p)
    {
        int i=0;
        int j=0;
        int* next=getNext(T);
        while (i < (int)T.length() && j < (int)p.length())
        {
            if (j == -1 || T[i] == p[j])
            {
                i++;
                j++;
            }
            else
            {
                j=next[j];
            }
        }
        if (j == (int)p.length())
        {
            return i-j;
        }
        return -1;
    }

推荐阅读更多精彩内容

  • 字符串匹配KMP算法详解 1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有...
    张晨辉Allen阅读 594评论 0 2
  • 原链接:KMP算法详解|CloudWong 传统的字符串匹配模式(暴力循环) 子串的定位操作通常称作串的串的匹配模...
    简Cloud阅读 1,629评论 1 17
  • 数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章、这篇文章、还有这篇他们写得非常...
    sunhaiyu阅读 650评论 1 21
  • 数据结构 第8讲 KMP算法 讲这个算法之前,我们首先了解几个概念: 串:又称字符串,是由零个或多个字符组成的有限...
    rainchxy阅读 367评论 0 3
  • 引言 字符串匹配一直是计算机科学领域研究和应用的热门领域,算法的改进研究一直是一个十分困难的课题。作为字符串匹配中...
    潮汐行者阅读 531评论 2 6