还是KMP,我觉得应该把自己的心得写一下。这题要求的是“前后辍”,即既是前辍又是后辍,比如“abcab”中的“ab”。KMP求next数组有两种算法,一种是:
if(t[i] == t[j])
{ i++; j++; next[i] = j; }
另一种是:
if(t[i] == t[j])
{ i++; j++;
if(t[i] != t[j])
next[i] = j;
else
next[i] = next[j];
}
第二种是第一种的改进版,不过这一题恰恰是第一种比较合适。对字串“ababcabab”来说,两种方法构造的next分另为:
a | b | a | b | c | a | b | a | b | |
-1 | 0 | -1 | 0 | 2 | -1 | 0 | -1 | 0 | 4 |
-1 | 0 | 0 | 1 | 2 | 0 | 1 | 2 | 3 |
4 |
在文中插表格太麻烦,我就做成这样了。上一行是第二种,下一行是第一种方法,从左到右分别为next[0]到next[10],第一种方法的数组满足这样的性质:对任意 i ,next[i] = j 表示字串中前 i 个字符组成的子串的最长“前后辍”长度为 j 。比如,‘c’ 对应着next[4] = 2,那么前4个字符“abab” 的最长前后辍“ab”的长度为2。这样就好办多了,“ababcabab” 的最长串为“abab”,“abab”的最长串为“ab”,递归打印就行了。
1 #include <stdio.h> 2 #include <string.h> 3 int next[1000005],len; 4 char T[1000005]; 5 void getnext(char *t) 6 { 7 int i=0,j=-1; 8 len = strlen(T); 9 next[0] = -1; 10 while(i < len) 11 if(j == -1 || T[i]==T[j]) 12 { 13 i++;j++; 14 next[i] = j; 15 } 16 else j = next[j]; 17 } 18 void show(int a) 19 { 20 if(next[a]) 21 show(next[a]), 22 printf(" %d",a); 23 else printf("%d",a); 24 } 25 int main() 26 { 27 while(~scanf("%s",T)) 28 { 29 getnext(T); 30 show(len); 31 printf("\n"); 32 } 33 return 0; 34 }
PS:刚刚才发现,第二种数组虽不对任意 i 满足上述性质,但是在这一题相应的位置上是满足的,晕死,那不就是两种都可以了。