URAL 1297 求最长回文字符串
有种简单的方法,数组从左到右扫一遍,每次以当前的点为中心,只要左右相等就往左右走,这算出来的回文字符串是奇数长度的
还有偶数长度的回文字符串就是以当前扫到的点和它左边的点作为中心,然后往左右扫
这是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 求最长回文字符串的更多相关文章
- URAL 1297 Palindrome 最长回文子串
POJ上的,ZOJ上的OJ的最长回文子串数据量太大,用后缀数组的方法非常吃力,所以只能挑个数据量小点的试下,真要做可能还是得用manacher.贴一下代码 两个小错,一个是没弄懂string类的sub ...
- 后缀数组 - 求最长回文子串 + 模板题 --- ural 1297
1297. Palindrome Time Limit: 1.0 secondMemory Limit: 16 MB The “U.S. Robots” HQ has just received a ...
- Manacher算法 - 求最长回文串的利器
求最长回文串的利器 - Manacher算法 Manacher主要是用来求某个字符串的最长回文子串. 不要被manacher这个名字吓倒了,其实manacher算法很简单,也很容易理解,程序短,时间复 ...
- 最长回文字符串(manacher算法)
偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid. 题目描述: 回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. ...
- PAT甲题题解-1040. Longest Symmetric String (25)-求最长回文子串
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789177.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- 【转载】最长回文字符串(manacher算法)
原文转载自:http://blog.csdn.net/lsjseu/article/details/9990539 偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid ...
- Manacher算法:求解最长回文字符串,时间复杂度为O(N)
原文转载自:http://blog.csdn.net/yzl_rex/article/details/7908259 回文串定义:"回文串"是一个正读和反读都一样的字符串,比如&q ...
- Manacher模板( 线性求最长回文子串 )
模板 #include<stdio.h> #include<string.h> #include<algorithm> #include<map> us ...
- [hdu3068 最长回文]Manacher算法,O(N)求最长回文子串
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文 ...
随机推荐
- 转】[MySQL优化]为MySQL数据文件ibdata1瘦身
原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/page/2/ 感谢! [MySQL优化]为MySQL数据文件ibda ...
- Android使用Gson(相当于C#的Newtonsoft.Json)非常好用
C#转Java有一段时间了,之前做ASP.NET WebAPI微软竟将第三方类库Newtonsoft.Json作为VS新建MVC和WebAPI项目默认必备的Json工具Nuget包,可想而知这个包有多 ...
- Java BigDecimal类的使用和注意事项
1.对于金额相关运算,若是精度较高,基本上用BigDecimal进行运算,精度要求低的话用Long.Double即可 2.web后台接受金额用String接受,展示到前端一般也转成 String 3. ...
- poj2991 Crane
思路: 线段树每个节点维护第一条线段起点指向最后一条线段终点的向量,于是每一个操作都是一次区间更新.使用成段更新的线段树即可.实现: #include <cstdio> #include ...
- mysql 判断null 和 空字符串
1.在mysql中null 不能使用任何运算符与其他字段或者变量(函数.存储过程)进行运算.若使用运算数据就可能会有问题. 2.对null 的判断: 创建一个user表:id 主健 name 可以为空 ...
- Java线程-线程、程序、进程的基本概念
线程 与进程相似,但线程是一个比进程更小的执行单位.一个进程在其执行的过程中可以产生多个线程. 与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间 ...
- Objective-C Memory Management 内存管理 2
Objective-C Memory Management 内存管理 2 2.1 The Rules of Cocoa Memory Management 内存管理规则 (1)When you c ...
- R Programming week1-Reading Data
Reading Data There are a few principal functions reading data into R. read.table, read.csv, for read ...
- H.264学习笔记1——相关概念
此处记录学习AVC过程中的一些基本概念,不定时更新. frame:帧,相当于一幅图像,包含一个亮度矩阵和两个色度矩阵. field:场,一帧图像,通过隔行扫描得到奇偶两场,分别称为顶场和底场或奇场和偶 ...
- 【译】x86程序员手册40-10.5初始化的例子
10.5 Initialization Example初始化的例子 译注:本来想把这个例子全部注释完,但由于对intel汇编实不熟悉,有太多的伪指令,本人也是免强看懂,所以就不再做翻译了. $TITL ...