KMP 字符串匹配算法 详解

前言:

记住代码并非学懂了算法,而是学会了做题。

真正学懂算法是能够教会别人。

引例:给定两个字符串S和T,问T是否属于S的子串。

这就是基本的字符串匹配问题,我们很容易想到暴力破解法。

暴力破解法:

为便于描述和理解,我们称S串为主串,T串为模式串。

在主串中枚举模式串的起点,若字符相同则继续向后匹配,不同则更新起点,重新开始匹配。

定义指针i、j

i:正在匹配主串第i个字符

j:已经匹配了模式串前j个字符

初始状态

主串待匹配字符s[i]='A'与模式串下一个字符t[j+1]='A'相同,匹配成功。指针后移,i++;j++。

同理,再经过一次匹配后,

主串待匹配字符s[i]='B'与模式串下一个字符t[j+1]='A'不同,匹配失败。更新枚举起点i=2,重新开始匹配,直到模式串已匹配字符数j==len(模式串长度)为止。

估算时间复杂度:O(n*m)

KMP算法:

KMP算法的本质是对暴力破解法的优化。删减无效操作,将可用信息重复利用。

我们先继续对上述过程的模拟,

经过数次更新起点与匹配后,我们得到以上状态。按照暴力破解法的流程,此刻匹配失败,由i=4为起点枚举而来,因而更新起点至i=5。

但实际上并不需要这样的操作,我们观察:

  设k,s[i-k]..s[i-2]s[i-1]=t[1]..t[k-1]t[k](s<i-k<=i-1

  若k不存在,那么以任何一点d(s<d<=i-1)为起点都无法匹配出模式串。①

  若k存在:

    若t[k+1]!=s[i],那么也无法匹配出模式串。

    若t[k+1]=s[i],则有可能以i-k为起点匹配出模式串。

①:都会因s[i-1]或之前的某个字符失配而断掉。

②:会因s[i]失配而断掉。

图1:不存在满足条件的k,从任意起点p(s<p<=i-1)都因某字符q匹配不到i-1

图2:存在满足条件的k,但t[k+1]!=s[i],因字符i匹配不到i-1

图3:既存在满足条件的k,t[k+1]=s[i],那么则有可能以i-k为起点匹配出模式串

因而,当匹配失败时,只需找到满足条件的k的最大值。若存在,主串向后匹配,以i-k为起点;若不存在,主串也向后匹配,寻找新的起点。

请思考,选择最大的k是否会漏掉可能的匹配起点?(答案见下文)

算法实现:

我们知道:s[s]..s[i-2]s[i-1]=t[1]..t[j-1]t[j]

  因为s<i-k<=i-1,

  所以s[i-k]..s[i-2]s[i-1]=t[j-k+1]..t[j-1]t[j]

因而我们只需要在模式串已匹配部分寻找k即可。

由于通常情况下模式串长度比较小,我们可以初始化出模式串中每个位置的k值。我们常用next[]数组存储模式串中每个位置的k值。

那么如何求得next[i]?

其实我们求得next[i]的过程等价于用模式串匹配自身的过程。为位置i寻找最长前缀后缀,可以想成用i前面的字符串去匹配模式串,到i最多能够匹配多长。这样以来问题就迎刃而解了,我们只需要进行两次匹配,一次求得next数组,一次匹配模式串。

注意:满足条件的k是指由i-k到i-1能够匹配模式串前k个字符,同时s[i+1]=t[k+1]!

算法流程:

1.初始化指针i=1,j=0

2.循环枚举主串待匹配字符i

3.枚举一个字符就对模式串进行一次匹配:

  若s[i]=t[j+1],则模式串第j+1个字符匹配成功,i++;j++

  若s[i]!=t[j+1],匹配失败,则更新j等于最长的满足条件的k,i++

4.当j=len时,匹配成功,跳出循环。

代码如下:

 1 void get_next()
 2 {
 3     int i,j;
 4     j=0;
 5     next[1]=0;
 6     for(i=2;i<=lent;i++){
 7         while(j>0&&t[j+1]!=t[i])j=next[j];
 8         if(t[j+1]==t[i])j++;
 9         next[i]=j;
10     }
11 }
12 
13 void KMP()
14 {
15     int i,j;
16      j=0;
17      for(i=1;i<=lens;i++){
18          while(j>0&&t[j+1]!=s[i])j=next[j];
19          if(t[j+1]==s[i])j++;
20          if(j==lent)ans[++cnt]=i-j+1;
21     }
22 }

next数组的求得很关键,这几天要期末考试,学业繁重。日后加图完善!

 

  

猜你喜欢

转载自www.cnblogs.com/Neat-Foxes/p/12098930.html