1. 程式人生 > >kmp最小迴圈節的求法

kmp最小迴圈節的求法

其實我一直都沒有理解嚴老師的資料結構中對於next函式求法中的一句話

next 函式求值可以看作是串的模式匹配問題,這句話我一直我不是很理解,我一直把它的過程理解為一個動態規劃的過程(有興趣的話可以參見上一篇文章),後來學長做的一個軟體讓我明白了


開始的時候,將t串的第一個字母的next值作為0,因為他沒有字首,第二個也是沒有後綴,所以他一定是1,但是不能直接將其賦值為1,因為的直接影響著下一個的遞推算值,如果相等就i++,j++next[i]=j了,從第三個值開始它就有字首和字尾了(注意,next[3]函式的意思不是求最大2~3個的字尾等於哪個字首,而是最大2~2個的最大字尾)所以next[10]=9;

把next的值看作模式匹配問題時候,下面的t串相當於字首,而上面的t串相當於字尾。

言歸正傳,我們來談論,求最小迴圈串的問題。

我們設想,我們可以利用next函式來求最小迴圈子串,我們看圖


當有迴圈節的時候,他會有大量的重合,從圖中可以看出strlen(T)-j<strlen(T)/2,strlen(T)-j達到最大時候就是隻迴圈兩次的時候,就是strlen(T)-j=strlen(T)/2

而沒有迴圈節時候,他的最後strlen(T)-j大於strlen(T)/2,最小的時候就是兩次迴圈的時候

所以,我們以strlen(T)%(strlen(T)-j)是否是0來判斷是否是有迴圈節,然後又用strlen(T)/(strlen(T)-j)來求出最小迴圈節的大小。

但是細心的讀者會發現我們是從0開始的,這樣strlen(T)會多一個,並且如果單純的減1,會因為不符合常理(取餘操作過不去)而被判斷為沒有迴圈節,所以,我們讓j在走一步,這個意思是說到達最後一個的時候,我們不讓他返回next[strlen(T)-1]而是返回最後一個j,這樣如果最後一個符合條件就會next[strlen(T)-1]++,如果最後一個不符合就會返回next[j],這樣不僅解決了strlen(T)的問題,而且解決了只迴圈兩次的問題,例如


這樣會返回next[4],也解決了只迴圈兩次的問題。