<题目链接>
最长回文
Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa
abab
Sample Output
4
3
//最长回文,Manacher算法 #include <iostream> #include <cstring> #include <string> #include <map> #include <queue> #include <algorithm> using namespace std; char s[211000], c[111000]; int len[211000]; //Len[i]表示以字符s[i]为中心的最长回文字串的最右字符到s[i]的长度 //转换字符串 void init() { int i, j; s[0] = '@'; //s[0]的初始化好像没什么用? for (i = 0; c[i] != 0; i++) { s[2 * i + 1] = '#'; s[2 * i + 2] = c[i]; } s[2 * i + 1] = '#'; s[2 * i + 2] = 0; } int manacher() { int id = 0, mx = 0, i; for (i = 1; s[i] != 0; i++) { // 2*id-i,指的是i关于id 对称得到的坐标 len[i] = mx>i ? min(len[2 * id - i], mx - i) : 1; //因为前面已经算过了mx前的每个点的回文串,所以,如果这个i点在mx范围内,就将len[i]初始化为前面算过的数值 while (s[i + len[i]] == s[i - len[i]])len[i]++; if (i + len[i]>mx) { mx = i + len[i]; //mx为前i个回文子串的右端点所能到达的最大距离,即前面已经算过的最大回文区域 id = i; //记录下这个回文字串的中心位置 } } int ans = 0; for (i = 1; s[i] != 0; i++) { if (len[i]>ans)ans = len[i]; //找到最大的len[i] } return ans - 1; //回文串长度为len[i]-1,这个可以自己画图理解,因为s[]数组是在原串的基础上插入了 '#' } int main() { while (~scanf("%s", c)) { init(); printf("%d\n", manacher()); } return 0; }
2018-08-04