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

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

这是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. multiset || 线段树 HDOJ 4302 Holedox Eating

    题目传送门 题意:一个长度L的管子,起点在0.n次操作,0 p表示在p的位置放上蛋糕,1表示去吃掉最近的蛋糕(如果左右都有蛋糕且距离相同,那么吃同方向的蛋糕),问最终走了多少路程 分析:用multis ...

  2. 员工管理系统(集合与IO流的结合使用 beta3.0 BufferedReader / ObjectOutputStream)

    Employee.java package cn.employee_io; public class Employee { private String empId; private String n ...

  3. mysql 中 时间函数 now() current_timestamp() 和 sysdate() 比较

    转载请注明出处 https://www.cnblogs.com/majianming/p/9647786.html 在mysql中有三个时间函数用来获取当前的时间,分别是now().current_t ...

  4. android开发学习——facebook第三方登录,看了你不会后悔

    给APP用原生android进行facebook第三方登录. 我们做一件事情,首先得了解其原理,这样才不会迷茫,才知道自己做到什么程度了,心里才会有底. 所以,第一步,了解第三方登录的原理:下面贴一些 ...

  5. Windows10系统切换JDK版本(前提是装了多个版本的JDK)

    由于是直接截屏,等我回过头来整理的时候忘记了文章原来的出处, 如作者本人看到,如有侵权,请联系删除!

  6. Oracle 表-初步涉水不深(第一天)

    oracle 关系型数据库 注释:面对大型数据处理,市场占有率40%多(但是目前正往分布式转换) 故事:本来一台大型计算机才能处理的数据,美国科学家用100台家用电脑连接,成功处理了数据.. tabl ...

  7. SpringMvc如何将Url 映射到 RequestMapping (二)

    昨天简单分析了Springmvc 中 RequestMapping 配置的url和请求url之间的匹配规则.今天详细的跟踪一下一个请求url如何映射到Controller的对应方法上 一.入口 org ...

  8. ubuntu个人初始配置记录

    1.安装vim编辑器 sudo apt-get install vim vim-gnome. vim有vim(vim-basic),vim-tiny,vim-gnome(gvim)等多个版本,安装ub ...

  9. struts2的action是线程安全的,struts1的action不是线程安全的真正原因

    为什么struts2的action是线程安全的,struts1的action不是线程安全的? 先对struts1和struts2的原理做一个简单的讲解 对于struts1 ,当第一次**.do的请求过 ...

  10. 数组(Arry)几个常用方法的详解

    join() 方法用于把数组中的所有元素放入一个字符串.元素是通过指定的分隔符进行分隔的. arrayObject.join(separator)separator 可选.指定要使用的分隔符.如果省略 ...