1. 程式人生 > >程式設計珠璣(四)求一個字串中連續出現的次數最多的子串

程式設計珠璣(四)求一個字串中連續出現的次數最多的子串

這個題目不是程式設計珠璣上看到的,但是解法用到的資料結構在程式設計珠璣上有講到,先歸類到這裡。

求一個字串中連續出現的次數最多的子串。例如字串“abababc”,最多連續出現的為ab,連續出現三次。要和求一個字串中的最長重複子串區分開來,還是上面的字串,那麼最長的重複子串為abab。兩個題目的解法有些類似,都用到了字尾陣列這個資料結構。求一個字串中連續出現的次數最多的子串,首先生成字尾陣列例如上面的字串為:
abababc
bababc
ababc
babc
abc
bc
c
可以看出第一個字尾陣列和第三個字尾陣列的起始都為ab,第5個字尾陣列也為ab。可以看出規律來,一個字串s,如果第一次出現在後綴陣列i的前面,那麼如果它重複出現,下一次出現應該在第i+len(s)個字尾陣列的前面。這個規律也不難看出。那麼從頭到尾按照這個規律搜尋下不難得出結果。下面是程式碼:

#include <iostream>
using namespace std;

int con_sub(char *str, char **ret);

int main()
{
        char str[] = "abcabcabcabcabcabbbb";
        char *ret = NULL;
        int time = con_sub(str, &ret);
        printf("%s occuers %d times\n", ret, time);
        return 0;
}

int con_sub(char *str, char **ret)
{
        int max_time = 0;//連續出現的最多次數
        int ret_len = 0;//連續出現的字串的長度
        char *addr = NULL;//連續出現字串的起始地址

        int len = strlen(str);
        char **a = (char **)malloc(sizeof(char *)*len);
        //生成字尾陣列
        for(int i=0; i<len; i++)
                a[i] = &str[i];

        //重複字串的長度範圍為1到(len+1)/2
        for(int i=1; i<=(len+1)/2; i++)
        {
                //當重複的字串長度為i的時候,如果是連續出現的,那麼第j和第j+i個字尾陣列前面為重複的字串
                for(int j=0; j+i<=len-1; j+=i)
                {
                        int k = j;
                        int temp_time = 1;
                        while(k+i <= len-1 && strncmp(a[k], a[k+i], i) == 0)
                        {
                                temp_time++;
                                k += i;
                        }
                        if(temp_time > max_time)
                        {
                                max_time = temp_time;
                                ret_len = i;
                                addr = a[k];
                        }
                }
        }
        *ret = new char[len+1];
        strncpy(*ret, addr, ret_len);
        return max_time;
}