poj1509 最小表示法
阿新 • • 發佈:2019-02-13
學習一下最小表示法……,部分內容與此題無關。
1.起始問題 :比較兩個字串是否迴圈同構 比如說abca和caab是迴圈同構的(abca和acba不是迴圈同構) 2.複雜度較高的演算法 例舉A串的所有迴圈同構串 和B串作比較:abca,bcaa,caab,aabc挨個和caab比一邊 複雜度O(N^2) 能否優化到O(N)? kmp演算法顯然可以,但是kmp是針對匹配的,不是專門針對同構的,顯得有些麻煩 3.最小表示法,就是充分利用迴圈同構的特點,進行比較的一種演算法,兩個串如果迴圈同構,會有什麼特點? 比如以上例舉的四個abca的迴圈同構串abca,bcaa,caab,aabc,如果有一種對映,這四個字串對應的對映值相同,那比較起來就太快了 我們利用字串的字典序,把這四個都對映到aabc,那就可以很快比較了,具體還有一些細化,利用最小表示的起始位置等等 具體的演算法和證明,周源2003年國家隊論文 寫的不錯
4.最小表示的最靠近串首的起始位置計算
abca的同構串中aabc最小,那麼要記錄下aabc開頭的a在abca中的位置,就不用記錄abca了,所以只要算出這個位置,就可以進行字串之間迴圈同構的比較
複雜度O(N)
我參考了這篇部落格http://blog.csdn.net/zy691357966/article/details/39854359
對於一個字串,i開始指向0,j開始指向1,演算法的過程中,i和j中小的數表示當前認為的合理位置,大的數表示從這個數開始可能會找到更合理的位置
(開始認為從最開始的位置是合理的 i= 0,只有在0後面才可能找到更合理的,所以j=1)
然後把字串複製一遍到末尾(方便迴圈)
每次從i+0和j+0開始比較,如果一直比較串長度個,都一樣,那麼恭喜你,i和j中的最小者就是答案了(為什麼自己想(實際上是我懶,要結合i和j所代表的意義))
如果比較到i+k和j+k不相等,結束迴圈 。
【下面這段是關鍵】
s(i,i+k-1)的每一位和s(j,j+k-1)的每一位對應相等,而如果s[i+k] > s[j+k],則i到s(i+x,i+k)顯然比s(j+x,j+k)大,(0<=x<=K)
那麼最小表示的開始位置就不可能是i到i+k【s(x,y)表示x到y的字串】
所以這個時候把i置為i+k+1,類似的,如果s[j+k] > s[i+k]就把j置為j+k+1
【上面那段是關鍵】
如果某一次加完之後i和j相等,那就和開始的時候一樣,不好比較了,這個時候把i或者j+1,繼續演算法
每一次這樣的迴圈結束後,如果i或者j超出m的範圍了,那麼另外一個就是解了!
上一下自己的程式碼……
1.起始問題 :比較兩個字串是否迴圈同構 比如說abca和caab是迴圈同構的(abca和acba不是迴圈同構) 2.複雜度較高的演算法 例舉A串的所有迴圈同構串 和B串作比較:abca,bcaa,caab,aabc挨個和caab比一邊 複雜度O(N^2) 能否優化到O(N)? kmp演算法顯然可以,但是kmp是針對匹配的,不是專門針對同構的,顯得有些麻煩 3.最小表示法,就是充分利用迴圈同構的特點,進行比較的一種演算法,兩個串如果迴圈同構,會有什麼特點? 比如以上例舉的四個abca的迴圈同構串abca,bcaa,caab,aabc,如果有一種對映,這四個字串對應的對映值相同,那比較起來就太快了 我們利用字串的字典序,把這四個都對映到aabc,那就可以很快比較了,具體還有一些細化,利用最小表示的起始位置等等 具體的演算法和證明,周源2003年國家隊論文
第一次發部落格,小緊張……有點捉急#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> using namespace std; int minpre(char s[]) { int m = strlen(s); memcpy(s + m, s,m*sizeof(char)); int i = 0,j = 1;//i表示從i往後是有可能的,j表示下一個試探的位置 while(j < m && i < m) { int k; for (k = 0;s[i + k] == s[j + k] && k < m; k++) if(k == m ) return min(i,j);//如果相等了,那最小的就是答案 if(s[i + k] > s[j + k]) i = i + k + 1;//i到i+k開始的都不可能 else (j = j + k + 1);//同上 if (i == j) j++;//剛好相等,重新比較 } if(i < m) return i; else return j; } int main() { char s[20005]; int n; scanf("%d",&n); while(n--) { scanf("%s",s); printf("%d\n",minpre(s) + 1); } }