题目来源:http://poj.org/problem?id=2752
Seek the Name, Seek the Fame
Time Limit: 2000MS |
Memory Limit: 65536K |
|
Total Submissions: 24318 |
Accepted: 12673 |
Description
The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm:
Step1. Connect the father's name and the mother's name, to a new string S.
Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S).
Example: Father='ala', Mother='la', we have S = 'ala'+'la' = 'alala'. Potential prefix-suffix strings of S are {'a', 'ala', 'alala'}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:)
Input
The input contains a number of test cases. Each test case occupies a single line that contains the string S described above.
Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000.
Output
For each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby's name.
Sample Input
ababcababababcabab
aaaaa
Sample Output
2 4 9 18
1 2 3 4 5
------------------------------------------------------------
题意
求字符串中各个公共前缀后缀(这题的前缀/后缀可以是字符串自身)的长度。例如”ababcababababcabab”的公共前缀后缀有:它自身以及”ababcaba”,”abab”,”ab”。
------------------------------------------------------------
思路
如果直接遍历整个字符串逐一判断前缀后缀是否一致,则遇到形如”aaaaa”的字符串时复杂度为O(n^2).
定义1:一个字符串所有公共前缀后缀(不含自身)中长度最长的公共前缀后缀成为“最大前缀后缀”。例如”ababcababababcabab”的最大公共前缀后缀是”ababcaba”
性质1:字符串的某个公共前缀后缀的公共前缀后缀也是该字符串的公共前缀后缀。
根据“性质1”,求一个字符串s(长度为n)的所有公共前缀后缀,只要找到它的最大公共前缀后缀s1,再找到s1的最大公共前缀后缀s2,……如此下去直到sn的最大公共前缀后缀为空字符串。这个过程复杂度为O(n).
于是问题转化为如何求一系列s[0:i](i=0,1,2,…,n-1)的最大公共前缀后缀。KMP算法中求next数组的函数就是解决这一问题的,其思想类似动态规划,复杂度为O(n),详见上一篇博文,在此就不赘述了。
--------------------提醒自己---------------------
一个好习惯,在for/while循环外先把循环条件里的strlen计算出来,不要在循环判断里每次计算(一开始TLE就是这个原因o(╥﹏╥)o)
------------------------------------------------------------
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
const int NMAX = 400005;
char str[NMAX] = {};
int next[NMAX] = {};
int ans[NMAX] = {};
void cal_next() // next[i]: str[0:(i-1)]的最大公共前缀后缀长度, 动态规划求next数组,O(n)
{
next[0] = -1;
int i = -1, j = 0, len = strlen(str);
while (j < len)
{
if (i == -1 || str[i] == str[j])
{
next[++j] = ++i;
}
else
{
i = next[i];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("2752.txt","r",stdin);
#endif
int i = 0, cnt = 0;
while (scanf("%s", str) != EOF)
{
cal_next();
i = strlen(str);
cnt = 0;
while (i > 0)
{
ans[cnt++] = i;
i = next[i]; // next数组回溯找最大前缀后缀的最大前缀后缀
}
for (i=cnt-1; i>=0; i--)
{
printf("%d ", ans[i]);
}
printf("\n");
}
return 0;
}