在KMP算法的使用中,首要任務就是獲取一個字符串的next數組,所以我們得明白next數組的含義(最好的方法是自己弄個例子,在草稿紙上模擬一下),在這里,通俗一點講,next[k] 表示,在模式串的 k 個字符失配了,然后下一次匹配從 next[k] 開始(next[k] 中保存的是該失配字符的前一個字符在前面出現過的最近一次失配的字符后面的一個字符的位置,有點繞口,自己寫個例子看看就明白了,也可以繼續往下看,有介紹,然后再自己嘗試寫寫 )。
至於next數組為什么可以用來求重復前綴呢,而且求出來的重復前綴是最小的呢?
next數組的求法:
void getnext(int len){ int i=0,j=-1; next[0]=-1; while(i<len){ if(j==-1 || str[i]==str[j]){ i++;j++; next[i]=j; }else j=next[j]; } }
個人認為,next數組在求解的過程中,用到了KMP的思想,當前失配了,就回溯到上一個next,請見 j=next[j] ,先說個結論,如果到位置 i ,如果有 i%(i-next(i))==0 , 那說明字符串開始循環了,並且循環到 i-1 結束,為什么這樣呢?
我們先假設到達位置 i-1 的時候,字符串循環了(到i-1完畢),那么如果到第i個字符的時候,失配了,根據next數組的求法,我們是不是得回溯?
然而回溯的話,由於字符串是循環的了(這個是假定的),next[i] 是不是指向上一個循環節的后面一個字符呢??
是的,上一個循環節的末尾是 next[i]-1 ,然后現在循環節的末尾是 i-1 ,然么循環節的長度是多少呢?
所以,我們有 (i - 1) - ( next[i] - 1 ) = i - next[i] 就是循環節的長度(假設循環成立的條件下),但是我們怎么知道這個循環到底成立嗎?
現在我們已經假設了 0————i-1 循環了,那么我們就一共有i 個字符了,如果有 i % ( i - next[i] ) == 0,總的字符數剛好是循環節的倍數,那么說明這個循環是成立的。
注意還有一點,如果 next[i] == 0,即使符合上述等式,這也不是循環的,舉個反例
0 1 2 3 4 5
a b c a b d
-1 0 0 0 1 2
下標為1,2,3的next值均為0,那么 i%(i-next【i】)=i%i==0,但是這個並不是循環。
解釋完畢,然后再來看下,為什么求出來的循環節長度是最小的呢?
因為next數組失配的時候,總是回溯到最近的循環節,所以i-next【i】就是最小的循環節長度
為什么求出來的循環次數是最多的呢?
循環節長度是最小的了,那么循環次數肯定是最多的了。
總結一下,如果對於next數組中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 則說明字符串循環,而且
循環節長度為: i - next[i]
循環次數為: i / ( i - next[i] )