KMP算法讲解

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,所以人们称它为克努特——莫里斯——普拉特操做(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽可能减小模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数自己包含了模式串的局部匹配信息。时间复杂度O(m+n)。ios

以上是百度百科对KMP算法的介绍,如何把实现把朴素算法变成O(m+n)的时间复杂度呢,从上面介绍能够看出来,KMP算法利用了一个next数组,因此须要预处理,下面咱们就来说解KMP算法。c++

由于懒得画图还怕画很差,因此我录制成了视频的格式。算法

Bilibili视频:https://www.bilibili.com/video/av40137935数组

这是一道KMP裸题,请自行尝试AC:传送门ide

看完上面,你大体就应该清楚如何利用KMP进行线性匹配了,可是KMP算法的精髓其实不是进行简单的串匹配,精髓应该在于next数组的应用,以及扩展的next_val数组的运用,能够快速的寻找循环节,前缀匹配等等一些复杂的字符串问题。函数

下面将以一道例题说明next数组的强大spa

HDU 1358(Period).net

Problem Description
For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K , that is A concatenated K times, for some string A. Of course, we also want to know the period K.
Input
The input file consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) - the size of the string S. The second line contains the string S. The input file ends with a line, having the number zero on it.
Output
For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.
SampleInput
3
aaa
12
aabaabaabaab
0
 
SampleOutput
Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

题意:给一个长为n的字符串,问字符串的前缀是否是周期串,若是是周期串,输出前缀的最后一个字母的位置和最短周期code

应该如何思考呢,已经说明了这是一道KMP的题,用KMP进行串匹配吗?显然不是,那么确定就是利用next数组的性质了,对于前i个字符,若是next[i]不等于零,那么说明在此字符串的前缀中,有一部分[0,next[i]]和本字符串[i-next[i],i]的这一部分是相同的。若是这i个字符组成一个周期串,那么错开的一部分[next[i],i]刚好是一个循环节。(换句话说,若是知足next[i]不等于零 && [next[i],i]是循环节这两点,就能够说明前i个字符组成一个周期串),那么咱们只须要跑一遍next数组便可,代码:视频

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n;
 5 string str;
 6 int nxt[1000005];
 7 
 8 void getnext(){
 9     int i = 0, j = -1, len = str.size();
10     nxt[0] = -1;
11     while(i < len){
12         if(j == -1 || str[i] == str[j])
13             nxt[++i] = ++j;
14         else
15             j = nxt[j];
16     }
17 }
18 
19 int main(){
20     ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0);
21     int tot = 1;
22     while(cin>>n && n){
23         cin>>str;
24         getnext();
25         cout << "Test case #" << tot++ << endl;
26         for(int i = 2; i <= n; i++){
27             if(nxt[i] != 0 && i % (i - nxt[i]) == 0)
28                 cout << i << " " << i/(i - nxt[i]) << endl;
29         }
30         cout << endl;
31     }
32 
33     return 0;
34 }

 

关于KMP算法就讲到这里了,这是一个很简单的串匹配算法,但可否掌握其思想以及运用其next数组,就得靠本身不断的磨练了。

相关文章
相关标签/搜索