有种简单的方法,数组从左到右扫一遍,每次以当前的点为中心,只要左右相等就往左右走,这算出来的回文字符串是奇数长度的

还有偶数长度的回文字符串就是以当前扫到的点和它左边的点作为中心,然后往左右扫

这是O(n^2)的复杂度,这道题过还是没有问题的

这里我主要练习的是另外的利用后缀数组加RMQ算法来解决这个问题

大致思想跟上面一致

首先将字符串反转贴在原字符串末尾,将字符通过ASCII码转化为字符,之间用一个1分开,最后贴一个0

然后得到它的后缀数组以及height[]数组

那么找回文字符也是扫一遍,每次以当前点作为偶数情况和奇数情况的中心

然后找到后来倒置的字符串对应字符的位置,这样二者的前缀一个是往前走的,一个是往后走的,正好贴一块就是回文的

但是这个查询为加快速度,就要用RMQ算法,求得区间内height数组的最小值

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
#define MAXN 2010
int sa[MAXN] , height[MAXN] , _rank[MAXN];
int wa[MAXN] , wb[MAXN] , wsf[MAXN] , wv[MAXN] , r[MAXN];
int dp[MAXN][];
char str[MAXN]; int cmp(int *r , int a , int b , int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
} void getSa(int *r , int *sa , int n , int m)
{
int i,j,p;
int *x=wa , *y=wb , *t; for(i= ; i<m ; i++) wsf[i]=;
for(i= ; i<n ; i++) wsf[x[i]=r[i]]++;
for(i= ; i<m ; i++) wsf[i]+=wsf[i-];
for(i=n- ; i>= ; i--) sa[--wsf[x[i]]]=i; p=;
for(j= ; p<n ; j*= , m=p)
{
for(p= , i=n-j ; i<n ; i++) y[p++]=i;
for(i= ; i<n ; i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i= ; i<n ; i++) wv[i]=x[y[i]];
for(i= ; i<m ; i++) wsf[i]=;
for(i= ; i<n ; i++) wsf[wv[i]]++;
for(i= ; i<m ; i++) wsf[i]+=wsf[i-];
for(i=n- ; i>= ; i--)sa[--wsf[wv[i]]]=y[i]; t=x , x=y , y=t;
x[sa[]]=;
for(i=,p=;i<n;i++)
x[sa[i]] = cmp(y , sa[i-] , sa[i] , j)?p-:p++;
}
return ;
} void callHeight(int *r , int *sa , int n)
{
int i,j,k=;
for(i= ; i<=n ; i++) _rank[sa[i]]=i;
// for(i=0 ; i<n ; i++) cout<<"_rank: "<<_rank[i]<<endl;
for(i= ; i<n ; height[_rank[i++]]=k)
for(k?k--: , j=sa[_rank[i]-]; r[i+k]==r[j+k] ; k++);
return ;
} void ST(int n)
{
//将height数组进行RMQ询问
memset(dp , 0x3f , sizeof(dp));
for(int i= ; i<=n ; i++) dp[i][]=height[i];
for(int j= ; (<<(j-))<n+ ; j++)
for(int i= ; i<=n ; i++)
dp[i][j] = min(dp[i][j-] , dp[i+(<<(j-))][j-]); return;
} int get_min(int s , int t)
{
int len = t-s+;
int l=floor(log(len*1.0)/log(2.0));
return min(dp[s][l] , dp[t-(<<l)+][l]);
} void solve(int n , int &left , int &right)
{
int ans = ;
//奇数情况
for(int i= ; i<n ; i++){
int j=*n-i;
int s=min(_rank[i] , _rank[j]);
int t=max(_rank[i] , _rank[j]);
int tmp = get_min(s+ , t);
if(ans<tmp*-){
ans = tmp*-;
left=i-tmp+ , right=i+tmp-;
}
}
//偶数情况
for(int i= ; i<n ; i++){
int j = *n-i+;
int s=min(_rank[i] , _rank[j]);
int t=max(_rank[i] , _rank[j]);
int tmp = get_min(s+ , t);
if(ans<tmp*){
ans = tmp*;
left=i-tmp , right=i+tmp-;
}
}
return;
} int main()
{
// freopen("a.in" , "r" , stdin);
while(~scanf("%s" , str))
{
int len = strlen(str);
r[len]=;
for(int i= ; i<len ; i++){
r[i] = (int)str[i];
r[*len-i] = r[i];
}
r[*len+]=; getSa(r , sa , *len+ , );
callHeight(r , sa , *len+);
//建立RMQ查询数组
ST(*len+);
int left= , right=;
solve(len , left , right);
str[right+]='\0';
printf("%s\n" , str+left);
}
return ;
}

URAL 1297 求最长回文字符串的更多相关文章

  1. URAL 1297 Palindrome 最长回文子串

    POJ上的,ZOJ上的OJ的最长回文子串数据量太大,用后缀数组的方法非常吃力,所以只能挑个数据量小点的试下,真要做可能还是得用manacher.贴一下代码 两个小错,一个是没弄懂string类的sub ...

  2. 后缀数组 - 求最长回文子串 + 模板题 --- ural 1297

    1297. Palindrome Time Limit: 1.0 secondMemory Limit: 16 MB The “U.S. Robots” HQ has just received a ...

  3. Manacher算法 - 求最长回文串的利器

    求最长回文串的利器 - Manacher算法 Manacher主要是用来求某个字符串的最长回文子串. 不要被manacher这个名字吓倒了,其实manacher算法很简单,也很容易理解,程序短,时间复 ...

  4. 最长回文字符串(manacher算法)

    偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid. 题目描述:      回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. ...

  5. PAT甲题题解-1040. Longest Symmetric String (25)-求最长回文子串

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789177.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  6. 【转载】最长回文字符串(manacher算法)

    原文转载自:http://blog.csdn.net/lsjseu/article/details/9990539 偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid ...

  7. Manacher算法:求解最长回文字符串,时间复杂度为O(N)

    原文转载自:http://blog.csdn.net/yzl_rex/article/details/7908259 回文串定义:"回文串"是一个正读和反读都一样的字符串,比如&q ...

  8. Manacher模板( 线性求最长回文子串 )

    模板 #include<stdio.h> #include<string.h> #include<algorithm> #include<map> us ...

  9. [hdu3068 最长回文]Manacher算法,O(N)求最长回文子串

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文 ...

随机推荐

  1. 数论(GCD) HDOJ 4320 Arcane Numbers 1

    题目传送门 题意:有一个A进制的有限小数,问能否转换成B进制的有限小数 分析:0.123在A进制下表示成:1/A + 2/(A^2) + 3 / (A^3),转换成B进制就是不断的乘B直到为0,即(1 ...

  2. c#中stringbuilder的方法总结

    String 对象是不可改变的.每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间.在需要对字符串执行重复修改的情况下,与创建新 ...

  3. java数据结构和算法04(链表)

    前面我们看了数组,栈和队列,大概就会这些数据结构有了一些基本的认识,首先回顾一下之前的东西: 在数组中,其实是分为有序数组和无序数组,我简单实现了无序数组,为什么呢?因为有序数组的实现就是将无序数组进 ...

  4. 函数的返回值return

    '''1.什么是返回值 返回值是一个函数的处理结果 2.为什么要有返回值 如果我们需要在程序中拿到函数的处理结果做进一步的处理,则需要函数必须有返回值 3.函数的返回值的应用 函数的返回值用retur ...

  5. 一个简单的公式——求小于N且与N互质的数的和

    首先看一个简单的东西. 若$gcd(i,n)=1$,则有$gcd(n-i,n)=1$ 于是在小于$n$且与$n$互质的数中,$i$与$n-i$总是成对存在,且相加等于$n$. 考虑$i=n-i$的特殊 ...

  6. Android 图片文件和Bitmap之间的转换

    String filePath="c:/01.jpg"; Bitmap bitmap=BitmapFactory.decodeFile(filePath); 如果图片过大,可能导致 ...

  7. 开发小Tips

    Kotlin语言篇: 1.抽象类的定义 abstract class Person(var name : String, var age : Int) : Any() { abstract var a ...

  8. 批处理 reg add /?

    C:\Users\Administrator>reg add /? REG ADD KeyName [/v ValueName | /ve] [/t Type] [/s Separator] [ ...

  9. wps 图片代码 复制 粘贴

    <table><tr><td><img src="C:\Users\Administrator\Desktop\QQ截图20160921180946 ...

  10. golang zip 解压、压缩文件

    package utils import (    "archive/zip"    "fmt"    "io"    "io/i ...