字串的最小表示法

2022-05-02 20:33:07 字數 2532 閱讀 9371

現在有個問題需要我們去解決,這個問題是這樣的:

有乙個字串,這個字串的首尾是連在一起的,要求尋找乙個位置,使得以該位置為起點的字串的字典序在所有的字串中最小

最最暴力的做法就是用o(n)的時間列舉起始位置,o(n)的時間比對字串的字典序,總的時間複雜度是o(n2),別想了,這種做法肯定不行。

那我們再來看乙個稍微樸素點的演算法(看的時候最好自己在草稿紙上模擬一下

我們設計ij兩個指標。其中i指向最小表示的位置,j作為比較指標。

初始時令i= 0,j= 1 

如果s[i]>s[j]i=j++

如果s[i]<s[j]j++

如果s[i]==s[j]設指標k,分別從ij位置向下比較,直到s[i+k]!=s[j+k]

如果s[i+k]>s[j+k]i=j++

否則j+=k+1

返回i

注意到,樸素演算法的缺陷在於斜體的情況下i指標的移動太少了。針對這一問題改進就得到了最小表示法的演算法。最小表示法的演算法思路是維護兩個指標ij

初始時令i=0,j=1 

如果s[i]>s[j]i=jj=i+1

如果s[i]<s[j]j++

如果s[i]==s[j]設指標k,分別從ij位置向下比較,直到s[i+k]!=s[j+k]

如果s[i+k]>s[j+k] i+=k+1

否則j+=k+1

返回ij的較小者

注意到上面兩個演算法唯一的區別是我用螢光筆刷出的那一行。這一行就把複雜度降到o(n)了。

為什麼會這樣呢?其實我開始看半天也不知道為什麼會這樣,我後來測試了一下,對於同一道題目,第使用一種演算法用了625ms,而第二種只用了16ms!!你就知道差別有多大了。

按我的理解來說,第一種演算法僅僅是用i維護了最小表示的位置,j不斷往後進行比較;而第二種演算法是比較完s[i+k]s[j+k]後根據情況來判斷ij誰才是最小表示位置,對應的另外乙個值去進行更新比較,這樣ij都能用來維護了最小表示的位置,效率會高上很多,妙啊~這種思想好像在哪兒見過,具體的已經忘了,不過以後碰到了理解起來也會更加容易

值得一提的是,可以應用最小表示法判斷兩個字串是否同構,與kmp類似,最小表示法處理的是乙個字串s的性質,而不是看**時給人感覺的處理兩個字串。 

只要將兩個串的最小表示求出來,然後從最小表示開始比較。剩下的工作就不用多說了。  

code

int

get_min()

}return i >j ?j :i;

}

view code

字串最小表示法

最小表示法的定義 給定乙個字串,不斷地把最後乙個元素移到最前面,可得有n個這樣的字串 稱這n個字串是迴圈同構的 那麼最小表示就是這n個裡面字典序最小的乙個 怎麼求最小表示 wrong 最樸素的方法,把每乙個這樣的字串求出來,然後一一比較,找到字典序最小的迴圈同構串 然後資料範圍變大肯定會超時 那麼正...

字串最小表示法

乙個長度為n的首尾相連的字串可以有n種表示法,例如串 abcd 還可以表示bcda,cdab,dabc當我們面臨這樣的字串的時候,我們很難統計相同字串的個數。因此我們引入一種字串的最小表示法來使這些串變得相同。字串的最小表示法是將原來的字串旋轉得到的字典序最小的串 設字串st的長度為len,我們可以...

字串的最小表示法

定義 給定乙個字串 s 1 n 如果我們不斷把他的最後乙個字元放到開頭,最終會得到 n 個字串,稱這 n 個字串是迴圈同構的。這些字串中字典序最小的乙個,稱為字串 s 的最小表示。例如 s abca 那麼它的 4 個迴圈同構字串為 abca aabc caab bcaa s 的最小表示為 aabc ...