KMP算法

Posted cccv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP算法相关的知识,希望对你有一定的参考价值。

 1 void Solution::KMPSearch(string pat, string txt)
 2 {
 3     int M = pat.length();
 4     int N = txt.length();
 5     int lps[M]; // 记录最长的相同的前缀后缀的长度
 6     computeLPSArray(pat, lps);
 7 
 8     int i = 0;
 9     int j = 0;
10     while(i < N)
11     {
12         if(pat[j] == txt[i])
13         {
14             i++;
15             j++;
16         }
17         if(j == M)
18         {
19             cout << "Found pattern at index " << i-j << endl;
20             j = lps[j-1];
21         } else if(i < N && pat[j] != txt[i])
22         {
23             if(j != 0)
24                 j = lps[j-1];
25             else
26                 i++;
27         }
28     }
29 
30 }
31 
32 
33 void Solution::computeLPSArray(string pat, int* lps)
34 {
35     int M = pat.length();
36     int i = 1;
37     int len = 0;
38     lps[0] = 0;
39 
40     while(i < M)
41     {
42         if(pat[i] == pat[len])
43         {
44             len++;
45             lps[i] = len;
46             i++;
47         }
48         else
49         {
50             if(len != 0)
51             {
52                 len = lps[len-1];
53             }
54             else
55             {
56                 lps[i] = 0;
57                 i++;
58             }
59         }
60     }
61 }

 

假设你对KMP算法有了解但感到困惑,本文不解释KMP算法的定义。

 

详细说一下KMP算法,刚看到的时候一头雾水,想不明白lps[]这个数组的作用。

在说明lps[]之前先说明一下最长的相同的前缀后缀的意思

比如字符串:"ababab"

前缀:"ababa", "abab", "aba" ,"ab", "a", "",

后缀:"babab", "abab", "bab", "ab", "b", "",

可以观察到最长的相同的前缀后缀在这里为"abab",长度为4

lps[]的作用就是记录字符串的最长的相同的前缀后缀的长度,这里长度为4,所以lps[5] = 4,

数组下标为5是因为字符串"ababab"的最后一个字符"b"的下标为5.(这里先不考虑lps[]是怎么实现的,明白它代表的意思就行了,后面会说明怎么实现的)

 

当我们知道最长的相同的前缀和后缀的长度,我们能用它来干什么呢?

“abab" 的最长的相同的前缀后缀为"ab",长度为2

所以"abab"的前2位 和 后2位相同

前缀:     (ab) ab

后缀:ab (ab)

假如当我们匹配两个字符串

pat = "abab" , txt = "ababab"

当第一次完全匹配时

a b a b a b

a b a b

此时i = 4, j = 4,根据算法此时打印找到的第一个下标,然后让j = lps[j-1] >> j = lps[3]

lps[3]保存的是"abab"的最长的相同的前缀后缀的长度,这里为”ab",所以长度为2,所以 j = 2;

因为在txt”ababab"找到的第一个字符串"abab"包含了要找的字符串"abab"的后两位“ab”,

而我们要找的字符串“abab”的前两位是"ab",所以我们可以直接跳过前两位,而从第三位字符"a"开始对比

因为"ab"长度为2,所以它的下一位的下标j应该为2,所以下一次循环为 if(pat[j] == txt[i]) >> if(pat[2] == txt[4]);

txt:a b   (a b)   a b

pat:       (a b)   a b

pat index  0 1    2 3

 

以上是关于KMP算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构—串KMP模式匹配算法

Python ---- KMP(博文推荐+代码)

KMP算法及Python代码

KMP算法及Python代码

图解KMP算法原理及其代码分析

Kmp算法Java代码实现