【题意简述】:如题,找出最长的回文字串!
【思路】:看完题的第一反应时枚举求解!但是数据量很大,字符串的长度可达1000000,若暴力求解,很明显会是O(n^2),所以一定会超时!
这里贴出我的超时代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
//#include<ctype> //在这个头文件中的isalpha(c),用于判断字符是否为大写!还有toupper用于返回字母的大写形式!
#define MAXN 1000000+5
char buf[MAXN],s[MAXN];
int main()
{
int n,m=0,max;
int i,j,k;
while(cin>>buf)
{
max = 0 ;
//fgets(buf,sizeof(s),stdin);
if(buf == "END") break;
m++;
n = strlen(buf);
/*for(i=0;i<n;i++)
if(isalpha(buf[i])) s[m++] = toupper(buf[i]);
*/
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
{
int ok =1;
for(k=i;k<=j;k++)
if(buf[k] != buf[i+j-k]) ok = 0;
if(ok && j-i+1>max) max = j-i+1;
}
cout<<"Case "<<m<<": "<<max<<endl;
}
return 0;
}
后来在看别人的解题报告后了解了,这个叫做Manacher 算法。
讲解可以看这里!http://www.cnblogs.com/lv-2012/archive/2012/11/15/2772268.html
我把他的代码贴出来,留作学习!
#include <stdio.h>
#include <memory>
const int MAX = 1000008;
char instr[MAX], str[MAX<<1];
int nRad[MAX<<1]; //点i 的对称半径
int maxRad;
int Mmin(int a, int b)
{
return a > b ? b : a;
}
void Manacher()
{
int i, j, maxx; //maxx 为匹配过的最大长度
int n = strlen(instr);
memset(str, '#', sizeof(str));
for (i=0; i<n; i++)
{
str[(i+1)<<1] = instr[i];
}
n = (n+1)<<1;
str[n] = '$';
maxRad = j = maxx = 0;
for (i=0; i<n; i++)
{
if (i < maxx)
{
//(maxx - i) 与 (2*j - i) 是以j为对称点.
//由于j之前的都是已经匹配过的了, 那么在以j为对称范围内,j的左边和右边都是对称的,那么j左边已经匹配过的点(2*j-i)和j右边的点i
//必有nRad[i] = nRad[2*j-i] 但是在nRad[2*j-i]中有可能超过j的匹配范围.
nRad[i] = Mmin(nRad[2*j - i] , maxx-i);
}
else nRad[i] = 1;
while (str[i - nRad[i]] == str[i + nRad[i]])
{
nRad[i]++;
}
if (maxRad < nRad[i])
{
maxRad = nRad[i];
}
if (nRad[i] + i > maxx)
{
j = i;
maxx = nRad[i] + i;
}
}
}
int main()
{
int t=1;
while (scanf("%s", &instr) !=EOF && instr[0] != 'E')
{
Manacher();
printf("Case %d: %d\n", t++, maxRad-1);
}
}