KMP求最小循環節講解
KMP最小循環節、循環周期:
定理:假設S的長度為len,則S存在最小循環節,循環節的長度L為len-next[len],子串為S[0…len-next[len]-1]。
(1)如果len可以被len - next[len]整除,則表明字符串S可以完全由循環節循環組成,循環周期T=len/L。
(2)如果不能,說明還需要再添加幾個字母才能補全。需要補的個數是循環個數L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。
理解該定理,首先要理解next數組的含義:next[i]表示前面長度為i的子串中,前綴和後綴相等的最大長度。
如:abcdabc
index |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
char |
a |
b |
c |
d |
a |
b |
C |
|
next |
-1 |
0 |
0 |
0 |
0 |
1 |
2 |
3 |
如對於a,ab,abc,abcd,很明顯,前綴和後綴相同的長度為0
對於長度為5的子串abcda,前綴的a和後綴的a相同,長度為1
對於長度為6的子串abcdab,前綴的ab和後綴的ab相同,長度為2
接下來舉幾個例子來說明最小循環節和循環周期:
為方便說明,先設字符串的長度為len,循環子串的長度為L
1.
s0s1s2s3s4s5 ,next[6]=3
即s0s1s2=s3s4s5
很明顯可知:循環子串為s0s1s2,L=len-next[6]=3,且能被len整除。
2.
s0s1s2s3s4s5s6s7 ,next[8]=6
此時len-next[8]=2 ,即L=2
由s0s1s2s3s4s5=s2s3s4s5s6s7
可知s0s1=s2s3,s2s3=s4s5,s4s5=s6s7
顯然s0s1為循環子串
3.
s0s1s2s3s4s5s6 ,next[7]=4
此時len-next[7]=3,即L=3
由s0s1s2s3=s3s4s5s6
可知s0s1=s3s4,s2s3=s5s6
從而可知s0s1s2=s3s4s5,s0=s3=s6
即如果再添加3-4%3=2個字母(s1s2),那麽得到的字符串就可以由s0s1s2循環3次組成
這個定理可以這麽理解:
http://www.cnblogs.com/oyking/p/3536817.html
對於一個字符串,如abcd abcd abcd,由長度為4的字符串abcd重復3次得到,那麽必然有原字符串的前八位等於後八位。
也就是說,對於某個字符串S,長度為len,由長度為L的字符串s重復R次得到,當R≥2時必然有S[0..len-L-1]=S[L..len-1],字符串下標從0開始
那麽對於KMP算法來說,就有next[len]=len-L。此時L肯定已經是最小的了(因為next的值是前綴和後綴相等的最大長度,即len-L是最大的,那麽在len已經確定的情況下,L是最小的)。
如果一定仔細證明的話,請看下面:
(參考來自:http://www.cnblogs.com/wuyiqi/archive/2012/01/06/2314078.html,有所改動)
k m x j i
由上,next【i】=j,兩段紅色的字符串相等(兩個字符串完全相等),s[k....j]==s[m....i]
設s[x...j]=s[j....i](xj=ji)
則可得,以下簡寫字符串表達方式
kj=kx+xj;
mi=mj+ji;
因為xj=ji,所以kx=mj,如下圖所示
k m a x j i
設s[a…x]=s[x..j](ax=xj)
又由xj=ji,可知ax=xj=ji
即s[a…i]是由s[a…x]循環3次得來的。
而且看到沒,此時又重復上述的模型,s[k…x]=s[m…j],可以一直遞推下去
最後可以就可以遞推出文章開頭所說的定理了。
最後再舉兩個相關例子
abdabdab len:8 next[8]:5
最小循環節長度:3(即abd) 需要補的個數是1 d
ababa len:5 next[5]:3
最小循環節長度:2(即ab) 需要補的個數是1 b
--------------------- 本文來自 hao_zong_yin 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/hao_zong_yin/article/details/77455285?utm_source=copy
KMP求最小循環節講解