1. 程式人生 > >如何利用KMP的next求字串的迴圈節 【轉】

如何利用KMP的next求字串的迴圈節 【轉】

點我看原文

利用KMP演算法中的next值可以求出字串的迴圈節,如ababab的迴圈節為ab,abcd的迴圈節為abcd,具體做法如下:假設字串的長度為len,next[len]為字串的最後一個字元的下一個字元的next值(下標從0開始),如果len % (len - next[len]) == 0,那麼迴圈節的迴圈次數為len / (len - next[len]),否則為1,為什麼呢?詳細說明如下:

首先,對於給定的長度為len的字串str,根據next的定義可知,str[0~(next[j]-1)] = str[(j-next[j])~(j-1)],且next[j]為滿足該條件的值當中的最大那一個,令迴圈次數為k,則

當k = 1時,根據next的意義可知next[len] = 0,所以len / (len - next[len]) = 1,結論正確;

當k = 2時,如abcdabcd,如果最後一個d後面還有字元的話,那麼它的next的值應該指向第二個a,為4,len % (len - next[len])= 8 % (8 - 4) = 0,迴圈次數為2,結論正確;

當k >= 3時,有len = k * (len - next[len])(x >= 3),next[len] = (1 - 1 / k) * len > (1 / 2) len,即next[len]位於字串的中間位置之後,如圖1所示,且黃色部分與藍色部分一樣,

如何利用KMP的next求字串的迴圈節   圖1

所以,在圖2中,紫色部分跟綠色部分也一樣(假設二者長度一樣),

如何利用KMP的next求字串的迴圈節   圖2

由於黃色部分跟藍色部分是一樣,且藍色部分結尾的兩段(紫色跟綠色)是一樣的,因而黃色部分在結尾部分也應該有兩段一樣的,即綠色跟它前面相同長度的一段,假設為紅色,此時紅色部分是藍色部分的倒數第三段,且跟前兩段一樣,這也將導致黃色部分也將產生倒數第三段,這樣,藍色部分的倒數第k段永遠是是黃色部分的倒數第k-1段,只要證明藍色跟黃色的公共部分是紫色部分的整數倍,那麼就可以說該公共部分是由n個紫色部分組成,由於藍色部分跟黃色部分長度一樣,二者又有公共部分,所以圖2中紅色部分跟紫色部分長度一樣,又因為整個字串長度是紫色部分的整數倍(>= 3),所以公共部分的長度也是紫色部分的整數倍(>= 1),如此一來,公共部分部分是由n個紫色部分組成(n >= 1),從而紅色部分跟紫色部分也必然一樣(紅色部分是黃色部分的跟紫色長度相同的第一部分),所以,整個字串是由n個紫色部分組成的(n >= 3),結論正確。

綜上所述,結論的充分性得證,另外,由next的意義可以很容易證明必要性。