51NOD 1088&1089 最长回文子串
回文串是指aba、abba、cccbccc、aaaa这种左右对称的字符串。
输入一个字符串Str,输出Str里最长回文子串的长度。
Input
输入Str(Str的长度 <= 1000(第二题要求为100000))
Output
输出最长回文子串的长度L。
Input示例
daabaac
Output示例
5
解:
1 #include <stdio.h> 2 3 int main() 4 { 5 char s[1005]; 6 while (scanf_s("%s", s, 1005) != EOF) 7 { 8 int max = 0; 9 for (int i = 0, j, a; s[i] != 0; i++) 10 { 11 for (j = 0; j <= i; j++) 12 if (s[i + j + 1] != s[i - j - 1])break; 13 a = j * 2 + 1; 14 max = a > max ? a : max; 15 for (j = 0; j <= i; j++) 16 if (s[i + 1 + j] != s[i - j]) 17 break; 18 a = j * 2; 19 max = a > max ? a : max; 20 } 21 printf("%d\n", max); 22 } 23 }
后来找了一些其他的解法,比较著名的是Manacher算法,它通过插入“#”的方式将我程序中的两类讨论变为了一种情况,避免了分类讨论,同时也优化了寻找过程。
Manacher实现:
1 #include <stdio.h> 2 3 #define CLR(x,len) memset(x, '#', len) 4 5 char s1[100005], s2[200005]; 6 int p[200005]; 7 8 int main() 9 { 10 while (scanf_s("%s", s1, 100005) != EOF) 11 { 12 int dis = 0, st = 0, i, len = (strlen(s1) << 1) + 1, ans = 0; 13 CLR(s2, len); 14 s2[len] = 0; 15 for (i = 0; s1[i] != 0; i++) s2[i << 1 | 1] = s1[i]; 16 for (i = 1 ; i < len; i++) 17 { 18 if (i < dis) p[i] = p[(st << 1) - i] > dis - i ? dis - i : p[(st << 1) - i]; 19 else p[i] = 0; 20 while (i - p[i] > 0 && s2[i + 1 + p[i]] == s2[i - 1 - p[i]]) p[i]++; 21 if (p[i] + i > dis) 22 { 23 dis = p[i] + i; 24 st = i; 25 ans = ans > p[i] ? ans : p[i]; 26 } 27 } 28 printf("%d\n", ans); 29 } 30 }
Manacher的另一种实现,优点是不需要加标记,但写起来容易出错
1 #include <stdio.h> 2 3 #define MIN(a,b) ((a)<(b)?(a):(b)) 4 #define CLR(x,len) memset(x, 0, len) 5 6 char s[100005]; 7 int dp[200005]; 8 int longestPalindrome(char * s); 9 int main() 10 { 11 while (scanf_s("%s", s, 100005) != EOF) 12 { 13 CLR(dp,200005); 14 printf("%d\n", longestPalindrome(s)); 15 } 16 } 17 int longestPalindrome(char * s){ 18 int dis=0,fg=0,ans[2]={0}; 19 char *p; 20 for(int i=0;s[dis+1]!='\0';++i) 21 { 22 int l=i>>1,t=i&1; 23 if(dis>l) dp[i]=MIN(dp[(fg<<1)-i],dis-l); 24 while(l-dp[i]+t>0&&s[l+dp[i]+1]==s[l-dp[i]-1+t]) ++dp[i]; 25 if(l+dp[i]>dis) 26 { 27 dis=l+dp[i]; 28 fg=i; 29 ans[t]=ans[t]>dp[i]?ans[t]:dp[i]; 30 } 31 } 32 return ans[1]>ans[0]?ans[1]<<1:(ans[0]<<1)+1; 33 }