求一個字符串中連續出現的次數最多的子串。例如字符串“abababc”,最多連續出現的為ab,連續出現三次。要和求一個字符串中的最長重復子串區分開來,還是上面的字符串,那么最長的重復子串為abab。兩個題目的解法有些類似,都用到了后綴數組這個數據結構。求一個字符串中連續出現的次數最多的子串,首先生成后綴數組例如上面的字符串為:
abababc
bababc
ababc
babc
abc
bc
c
可以看出第一個后綴數組和第三個后綴數組的起始都為ab,第5個后綴數組也為ab。可以看出規律來,一個字符串s,如果第一次出現在后綴數組i的前面,那么如果它重復出現,下一次出現應該在第i+len(s)個后綴數組的前面。這個規律也不難看出。那么從頭到尾按照這個規律搜索下不難得出結果。下面是代碼:
1 #include <iostream> 2 using namespace std; 3 4 int con_sub(char *str, char **ret); 5 6 int main() 7 { 8 char str[] = "abcabcabcabcabcabbbb"; 9 char *ret = NULL; 10 int time = con_sub(str, &ret); 11 printf("%s occuers %d times\n", ret, time); 12 return 0; 13 } 14 15 int con_sub(char *str, char **ret) 16 { 17 int max_time = 0;//連續出現的最多次數 18 int ret_len = 0;//連續出現的字符串的長度 19 char *addr = NULL;//連續出現字符串的起始地址 20 21 int len = strlen(str); 22 char **a = (char **)malloc(sizeof(char *)*len); 23 //生成后綴數組 24 for(int i=0; i<len; i++) 25 a[i] = &str[i]; 26 27 //重復字符串的長度范圍為1到(len+1)/2 28 for(int i=1; i<=(len+1)/2; i++) 29 { 30 //當重復的字符串長度為i的時候,如果是連續出現的,那么第j和第j+i個后綴數組前面為重復的字符串 31 for(int j=0; j+i<=len-1; j+=i) 32 { 33 int k = j; 34 int temp_time = 1; 35 while(k+i <= len-1 && strncmp(a[k], a[k+i], i) == 0) 36 { 37 temp_time++; 38 k += i; 39 } 40 if(temp_time > max_time) 41 { 42 max_time = temp_time; 43 ret_len = i; 44 addr = a[k]; 45 } 46 } 47 } 48 *ret = new char[len+1]; 49 strncpy(*ret, addr, ret_len); 50 return max_time; 51 }
注意:這里有一個小技巧,加入字符串中存在出現次數相同的子串,如何優先選擇更長的字符串作為最終的結果?可以調整子串的長度為從大到小。