最大最小表示法

循環字符串的最小表示法的問題可以這樣描述:

對於一個字符串S,求S的循環的同構字符串S’中字典序最小的一個。

由於語言能力有限,還是用實際例子來解釋比較容易:
設S=bcad,且S’是S的循環同構的串。S’可以是bcad或者cadb,adbc,dbca。而且最小表示的S’是adbc。
對於字符串循環同構的最小表示法,其問題實質是求S串的一個位置,從這個位置開始循環輸出S,得到的S’字典序最小。
一種樸素的方法是設計i,j兩個指針。其中i指向最小表示的位置,j作爲比較指針。

令i=0,j=1
如果S[i] > S[j] i=j, j=i+1
如果S[i] < S[j] j++
如果S[i]==S[j] 設指針k,分別從i和j位置向下比較,直到S[i] != S[j]
         如果S[i+k] > S[j+k] i=j,j=i+1
         否則j++
返回i

起初,我想在j指針後移的過程中加入一個優化。就是j每次不是加1,而是移動到l位置。其中,l>j且S[l]<=S[j]。但是,即使加入這一優化,在遇到bbb…bbbbbba這樣的字符串時複雜度將退化到O(n^2)。

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

令i=0,j=1
如果S[i] > S[j] i=j, j=i+1
如果S[i] < S[j] j++
如果S[i]==S[j] 設指針k,分別從i和j位置向下比較,直到S[i] != S[j]
         如果S[i+k] > S[j+k] i=i+k
         否則j++
返回i和j的小者

注意到上面兩個算法唯一的區別是粗體的一行。這一行就把複雜度降到O(n)了。
值得一提的是,與KMP類似,最小表示法處理的是一個字符串S的性質,而不是看論文時給人感覺的處理兩個字符串。
應用最小表示法判斷兩個字符串同構,只要將兩個串的最小表示求出來,然後從最小表示開始比較。剩下的工作就不用多說了。

  1. int MinimumRepresentation(char *s, int l)  
  2. {  
  3.     int i = 0, j = 1, k = 0, t;  
  4.     while(i < l && j < l && k < l) {  
  5.         t = s[(i + k) >= l ? i + k - l : i + k] - s[(j + k) >= l ? j + k - l : j + k];  
  6.         if(!t) k++;  
  7.         else{  
  8.             if(t > 0) i = i + k + 1;  
  9.             else j = j + k + 1;  
  10.             if(i == j) ++ j;  
  11.             k = 0;  
  12.         }  
  13.     }  
  14.     return (i < j ? i : j);  
  15. }  

然後主函數 設置變量 = 所求的, 循環輸出, 不斷++, %=n就好了


代碼:

  1. int getMin(char *s)
  2. {
  3. int i = 0, j = 1, l;
  4. int len = strlen(s);
  5. while(i < len && j < len)
  6. {
  7. for(l = 0; l < len; l++)
  8. if(s[(i + l) % len] != s[(j + l) % len]) break;
  9. if(l >= len) break;
  10. if(s[(i + l) % len] > s[(j + l) % len])
  11. {
  12. if(i + l + 1 > j) i = i + l + 1;
  13. else i = j + 1;
  14. }
  15. else if(j + l + 1 > i) j = j + l + 1;
  16. else j = i + 1;
  17. }
  18. return i < j ? i : j;
  19. }
  20. int getMax(char *s)
  21. {
  22. int len = strlen(s);
  23. int i = 0, j = 1, k = 0;
  24. while(i < len && j < len && k < len)
  25. {
  26. int t = s[(i+k)%len]-s[(j+k)%len];
  27. if(!t) k++;
  28. else
  29. {
  30. if(t > 0)
  31. {
  32. if(j+k+1 > i) j = j+k+1;
  33. else j = i+1;
  34. }
  35. else if(i+k+1 > j) i = i+k+1;
  36. else i = j+1;
  37. k = 0;
  38. }
  39. }
  40. return i < j ? i : j;
  41. }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章