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(有点小坑)