現在有個問題需要我們去解決,這個問題是這樣的:
有乙個字串,這個字串的首尾是連在一起的,要求尋找乙個位置,使得以該位置為起點的字串的字典序在所有的字串中最小。最最暴力的做法就是用o(n)的時間列舉起始位置,o(n)的時間比對字串的字典序,總的時間複雜度是o(n2),別想了,這種做法肯定不行。
那我們再來看乙個稍微樸素點的演算法(看的時候最好自己在草稿紙上模擬一下)
我們設計i,j兩個指標。其中i指向最小表示的位置,j作為比較指標。
初始時令i= 0,j= 1注意到,樸素演算法的缺陷在於斜體的情況下i指標的移動太少了。針對這一問題改進就得到了最小表示法的演算法。最小表示法的演算法思路是維護兩個指標i,j。如果s[i]>s[j]則i=j++
如果s[i]<s[j]則j++
如果s[i]==s[j]設指標k,分別從i和j位置向下比較,直到s[i+k]!=s[j+k]
如果s[i+k]>s[j+k]則i=j++
否則j+=k+1
返回i
初始時令i=0,j=1注意到上面兩個演算法唯一的區別是我用螢光筆刷出的那一行。這一行就把複雜度降到o(n)了。如果s[i]>s[j]則i=j,j=i+1
如果s[i]<s[j]則j++
如果s[i]==s[j]設指標k,分別從i和j位置向下比較,直到s[i+k]!=s[j+k]
如果s[i+k]>s[j+k] i+=k+1
否則j+=k+1
返回i和j的較小者
為什麼會這樣呢?其實我開始看半天也不知道為什麼會這樣,我後來測試了一下,對於同一道題目,第使用一種演算法用了625ms,而第二種只用了16ms!!你就知道差別有多大了。
按我的理解來說,第一種演算法僅僅是用i維護了最小表示的位置,j不斷往後進行比較;而第二種演算法是比較完s[i+k]和s[j+k]後根據情況來判斷i和j誰才是最小表示位置,對應的另外乙個值去進行更新比較,這樣i和j都能用來維護了最小表示的位置,效率會高上很多,妙啊~這種思想好像在哪兒見過,具體的已經忘了,不過以後碰到了理解起來也會更加容易
值得一提的是,可以應用最小表示法判斷兩個字串是否同構,與kmp類似,最小表示法處理的是乙個字串s的性質,而不是看**時給人感覺的處理兩個字串。
只要將兩個串的最小表示求出來,然後從最小表示開始比較。剩下的工作就不用多說了。
code
intview codeget_min()
}return i >j ?j :i;
}
字串最小表示法
最小表示法的定義 給定乙個字串,不斷地把最後乙個元素移到最前面,可得有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 ...