标签:
给出一个字符串S,S可能是多个较短的字符串的重复连接。比如"ababab"为字符串"ab"重复三次的结果;"abc" 为"abc"重复一次的结果;"abababab"可能是"abab"重复两次,也可能是"ab"重复四次的结果。
对一个给定的字符串S,求出最大的k,使得它为某个子串A重复k次的结果。
有了kmp的next数组(存储某子串的最长相同前后缀的长度),可以在此基础上分析。字符串S的子串A越短,则重复次数越多。
(1)显然,对于一个最多含有K个重复的A构成的串S,S的最长相同前后缀S1为K-1个A重复的结果;
(2)若S的最长相同前后缀S1和S确定的剩余部分S-S1(记为子串B)不能通过多个连接起来形成S1或者S,那么S必定无法分解为多个子串相连接的结果。
证明性质(2),若S-S1(记为A)不能拼成S或者S1,而S可以由多个子串拼接而成。假设S由P(不是最大的)个相同的子串B构成,那么P-1个B连接起来一定为S的相同前后缀(不一定为最长相同前后缀),且该相同前后缀的长度必定大于 strlen(S)/2,则strlen(S1)必定大于strlen(S)/2,则S的最长相同前后缀在S中必定相交!
对于串S,若他的最长前后缀相交,则可以肯定 S 由K个(S-S1)拼接而成。(通过画图可以说明)
#define _CRT_SECURE_NO_WARNINGS #define MAX_WORD_LEN 1000005 #include<stdio.h> #include<string.h> int gNext[MAX_WORD_LEN]; char gWord[MAX_WORD_LEN]; int gLength[MAX_WORD_LEN]; void GenerateNext(const char* sub_str, int* next, int len){ next[0] = 0; //next[i]表示sub_str[0, i]中最长相同前后缀的长度 for (int i = 1; i < len; i++){ int j = next[i - 1]; while (sub_str[j] != sub_str[i]){ //不断回溯,每次利用next数组来确定下一个需要判断的位置 if (j == 0){ j = -1; break; } j = next[j - 1]; } if (j < 0) next[i] = 0; else next[i] = j + 1; } } int main(){ while (scanf("%s", gWord) != EOF){ if (strcmp(gWord, ".") == 0){ break; } int len = strlen(gWord); GenerateNext(gWord, gNext, len); if (len % (len - gNext[len - 1]) == 0){ printf("%d\n", len / (len - gNext[len -1])); } else printf("1\n"); } return 0; }
标签:
原文地址:http://www.cnblogs.com/gtarcoder/p/4813794.html