【理解字符串循环同构的最小表示法】

【理解字符串循环同构的最小表示法】

分类:  ACM/ICPC2010-04-09 16:35  1504人阅读  评论(0)  收藏  举报
算法 优化 语言 工作

循环字符串的最小表示法的问题可以这样描述:

对于一个字符串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的性质,而不是看论文时给人感觉的处理两个字符串。
应用最小表示法判断两个字符串同构,只要将两个串的最小表示求出来,然后从最小表示开始比较。剩下的工作就不用多说了。

[cpp]  view plain copy
  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);  
 

【字符串最小(大)表示法+KMP求循环节】hdoj 3374 String Problem

分类: ACM/ICPC   692人阅读  评论(0)  收藏  举报
string output input each

首先用 字符串最小(大)表示法 解决第一个问题

然后用 KMP求循环节 解决第二个问题

 

[cpp]  view plain copy
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #define NUM 1000005  
  4.   
  5. void getnext(char str[],int next[])     
  6. {     
  7.     next[0] = -1;     
  8.     int i=0;     
  9.     int j=-1;     
  10.     int len = strlen(str);  
  11.     while (i<len)     
  12.     {     
  13.         if (j==-1||str[i]==str[j])     
  14.         {     
  15.             i++;     
  16.             j++;     
  17.             next[i] = j;     
  18.         } else {     
  19.             j=next[j];     
  20.         }     
  21.     }     
  22. }  
  23.   
  24. int MinAndMaxRepresentation(char *s, bool bMin = true)  
  25. {  
  26.     int i = 0, j = 1, k = 0, l = strlen(s), sub;  
  27.     while (i<l && j<l && k<l)  
  28.     {  
  29.         sub = s[(i+k)%l] -  s[(j+k)%l];  
  30.         if (sub == 0)  
  31.             k++;  
  32.         else  
  33.         {  
  34.             if (bMin?sub > 0:sub < 0)  
  35.                 i += k+1;  
  36.             else  
  37.                 j += k+1;  
  38.             if (i == j)  
  39.                 j++;  
  40.             k = 0;  
  41.         }  
  42.     }  
  43.     return i<j?i:j;  
  44. }  
  45. char str[NUM];  
  46. int next[NUM];  
  47. int main()  
  48. {  
  49.     int len;  
  50.     int minlen;  
  51.     int num;  
  52.     while (scanf("%s", str) != EOF)  
  53.     {  
  54.         len = strlen(str);  
  55.         getnext(str, next);  
  56.         if (len % (len-next[len]) == 0)  
  57.             minlen = len-next[len];  
  58.         else  
  59.             minlen = len;  
  60.         num = len / minlen;  
  61.         //printf("%d/n", minlen);  
  62.         printf("%d %d %d %d/n", MinAndMaxRepresentation(str)+1, num, MinAndMaxRepresentation(str, false)+1, num);  
  63.     }  
  64.     return 0;  
  65. }  
  66. /* 
  67. String Problem 
  68. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 
  69. Total Submission(s): 290    Accepted Submission(s): 110 
  70.  
  71.    
  72. Problem Description 
  73. Give you a string with length N, you can generate N strings by left shifts. For example let consider the string “SKYLONG”, we can generate seven strings: 
  74. String Rank  
  75. SKYLONG 1 
  76. KYLONGS 2 
  77. YLONGSK 3 
  78. LONGSKY 4 
  79. ONGSKYL 5 
  80. NGSKYLO 6 
  81. GSKYLON 7 
  82. and lexicographically first of them is GSKYLON, lexicographically last is YLONGSK, both of them appear only once. 
  83. Your task is easy, calculate the lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), its times, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also. 
  84.  
  85.    
  86.  
  87.   Input 
  88.   Each line contains one line the string S with length N (N <= 1000000) formed by lower case letters. 
  89.    
  90.  
  91.   Output 
  92.   Output four integers separated by one space, lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), the string’s times in the N generated strings, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also. 
  93.    
  94.  
  95.   Sample Input 
  96.   abcder 
  97.   aaaaaa 
  98.   ababab 
  99.    
  100.  
  101.   Sample Output 
  102.   1 1 6 1 
  103.   1 6 1 6 
  104.   1 3 2 3 
  105. */  


你可能感兴趣的:(ACM/ICPC)