首页 > 代码库 > KMP算法总结

KMP算法总结

KMP

 

窗外的麻雀,在电线杆上多嘴~~

  ta说这一句,很有寒假的感觉~

 

首先

#define ls 母串长度

#define lt 子串长度

 

在这寒假即将到来之际(2017.1.14),我们学习了KMP算法

KMP算法,异常nb的字串匹配算法

关于字串匹配,我们最开始都是(ls*lt)的暴力

  *超时稳稳的

具体就是枚举每个起点,然后起点往后推lt长度来比较是否一样

实在是太慢了

  所以,人们开发了KMP算法

KMP是怎么来弄的时间复杂度的呢?

不急,一步一步慢慢讲(记录子串靠后的元素的部分前缀在在子串中从0开始的位置)

 

KMP的关键在于next数组

next数组是什么呢?

next数组记录的是子串靠后的元素的部分前缀在子串中从0开始的位置

有点难理解,我们来分析一下

a b c a b d

它对应的next数组的值是

a b c a b d

0 0 0 1 2 0

你会发现子串前三个元素(abc)之后还有两个已经出现的元素(ab)

所以,(ab)中的a可以对应(abc)中的a,它的next值是1

(ab)中的b可以对应(abc)中的b,它的next值是2

附求next代码:

inline void GetNext(){    int k=-1,j=0;    next[j]=k;    while(j<lt)    {        if(k==-1||t[j]==t[k])        {            k++,j++;            next[j]=k;        }        else k=next[k];    }}

然后,我们就可以利用这个来优化

怎么优化呢?

两个指针i,j

i表示当前在母串中的位置

j表示当前在子串中的位置

刚开始i,j的初始值都是0

  然后,当s[i]==t[j](当前位置的数匹配)时,i++,j++,开始下一个位置的匹配

然后当i!=j时,即不匹配时,我们开始从j往前回溯

怎么回溯呢

j=next[j]

然后我们的时间就被优化了(仔细思考会发现是个线性的复杂度ls+lt)

附kmp代码:

inline int Kmp(){    //求出现的次数    GetNext();    int i=0,j=0,return_=0;    while(i<ls)    {        if(j==-1||s[i]==t[j]) i++,j++;        else j=next[j];        if(j==lt)        {            j=next[j];            return_++;        }    }    return return_;}

 

现在说两道关于kmp的裸题:

  洛谷 3375

  poj 3461(有点小坑)

KMP算法总结