题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068

题意:求一个字符串的最长回文子串

思路:

  • 枚举子串的两个端点,根据回文串的定义来判断其是否是回文串并更新答案,复杂度O(N3)。
  • 枚举回文串的对称轴i,以及回文半径r,由i和r可确定一个子串,然后暴力判断即可。复杂度O(N2)。
  • 在上一步的基础上,改进判断子串是否是回文串的算法。记fi(r)=(bool)以i为对称轴半径为r的子串是回文串,fi(r)的值域为{0, 1},显然fi(r)是关于r的单调函数,于是可以二分r,然后用字符串hash在O(1)的时间内判断子串是否是回文串,总复杂度O(NlogN)。
  • 虽然O(NlogN)的复杂度已经非常不错了,但还有线性的算法---Manacher算法。

Manacher算法:维护两个值r和id,r是以前的回文串的最大右边界,id是其对应的下标,如果当前考虑的对称轴i小于等于r,那么从i到r这一段子串是否可以和i左边的子串构成回文串(或者说最长能有多长)其实在之前是已经计算过了的(或者说计算出了一部分),因为将i作关于id的对称点i'=2*id-i,就不难发现i'周围若干字符和i周围若干字符是对应相同的,这是Manacher算法的核心之处,可以用i'的最大回文半径来更新i的最大回文半径,利用这个性质就能做到线性的复杂度。

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#pragma comment(linker, "/STACK:10240000")
#include <bits/stdc++.h>
using namespace std; #define X first
#define Y second
#define pb push_back
#define mp make_pair
#define all(a) (a).begin(), (a).end()
#define fillchar(a, x) memset(a, x, sizeof(a)) typedef long long ll;
typedef pair<int, int> pii; #ifndef ONLINE_JUDGE
namespace Debug {
void print(){cout<<endl;}template<typename T>
void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>
void print(T*p, T*q){int d=p<q?:-;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
}
#endif // ONLINE_JUDGE
template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}
template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}
/* -------------------------------------------------------------------------------- */ const int maxn = 3e5 + ; /** 求字符串每个位置的最大回文半径,在字符串中找最长回文子串 **/
struct Manacher {
int p[maxn];/** 回文半径 **/
char s[maxn];
void init(char str[]) {
strcpy(s, str);
int n = strlen(s);
s[n * + ] = ;
for (int i = n * ; i; i -= ) {
s[i] = '#';
s[i - ] = s[i / - ];
}
s[] = '#';
}
/** 求每个点的最大回文半径 **/
void work() {
int r = , id = ;
p[] = ;
for (int i = ; s[i]; i ++) {
p[i] = i <= r? min(r - i + , p[ * id - i]) : ;
if (p[i] >= r - i + ) {
r = (id = i) + p[i] - ;
while ( * i - r - >= && s[r + ] == s[ * i - r - ]) {
r ++;
p[i] ++;
}
}
}
}
/** 求最长回文串的长度 **/
int solve() {
work();
int ans = ;
for (int i = ; s[i]; i ++) {
ans = max(ans, p[i] - );
}
return ans;
}
};
Manacher solver; char s[maxn]; int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
while (~scanf("%s", s)) {
solver.init(s);
printf("%d\n", solver.solve());
}
return ;
}

[hdu3068 最长回文]Manacher算法,O(N)求最长回文子串的更多相关文章

  1. Manacher算法 O(n) 求最长回文子串

    转自:http://bbs.dlut.edu.cn/bbstcon.php?board=Competition&gid=23474 其实原文说得是比较清楚的,只是英文的,我这里写一份中文的吧. ...

  2. HDU3068 最长回文 Manacher算法

    Manacher算法是O(n)求最长回文子串的算法,其原理很多别的博客都有介绍,代码用的是clj模板里的,写的确实是异常的简洁,现在的我只能理解个大概,下面这个网址的介绍比较接近于这个模板,以后再好好 ...

  3. hdu 3068 最长回文 manacher算法(视频)

    感悟: 首先我要Orz一下qsc,我在网上很难找到关于acm的教学视频,但偶然发现了这个,感觉做的很好,链接:戳戳戳 感觉这种花费自己时间去教别人的人真的很伟大. manacher算法把所有的回文都变 ...

  4. hdu_3068 最长回文(Manacher算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 最长回文 Time Limit: 4000/2000 MS (Java/Others)    M ...

  5. hdu-3068-最长回文(manacher算法模板)

    题目链接 /* Name:hdu-3068-最长回文 Copyright: Author: Date: 2018/4/24 16:12:45 Description: manacher算法模板 */ ...

  6. [算法] Manacher算法线性复杂度内求解最长回文子串

    参考:http://www.felix021.com/blog/read.php?2040 以上参考的原文写得很好,解析的非常清楚.以下用我自己的理解,对关键部分算法进行简单的描述: 回文的判断需要完 ...

  7. HDU 3068 最长回文 Manacher算法

    Manacher算法是个解决Palindrome问题的O(n)算法,能够说是个超级算法了,秒杀其它一切Palindrome解决方式,包含复杂的后缀数组. 网上非常多解释,最好的解析文章当然是Leetc ...

  8. HDU 3068 最长回文 manacher 算法,基本上是O(n)复杂度

    下面有别人的比较详细的解题报告: http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html 下面贴我的代码,注释在代码中: #include ...

  9. 字符串-回文-Manacher算法

    http://blog.csdn.net/zzkksunboy/article/details/72600679 https://segmentfault.com/a/1190000008484167 ...

随机推荐

  1. 最短路径变形 POJ 2253

    Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sit ...

  2. cucumber学习索引

    Cucumber(1) —— 环境配置 Cucumber(2)——目录结构以及基本语法 Cucumber(3)——命令以及日志 Cucumber(4)——jenkins的集成

  3. 容易忽略的CSS3属性

    flex布局模型 1. flex-direction: row |  row-reverse | column | column-reverse flex-direction 属性决定主轴的方向(即项 ...

  4. [Asp.Net Core] Blazor Server Side 项目实践 - 切换页面时保留状态

    前言: 这是 项目实践系列 , 算是中高级系列博文, 用于为项目开发过程中不好解决的问题提出解决方案的. 不属于入门级系列. 解释起来也比较跳跃, 只讲重点. 因为有网友的项目需求, 所以提前把这些解 ...

  5. memcache雪崩

    缓存雪崩一般是由某个缓存节点失效,导致其他节点的缓存命中率下降, 缓存中缺失的数据(memcache经典场景,当有一个客户端的服务请求过来的时候,首先去查memcache,memcache里面是否缓存 ...

  6. 2019-2020-1 20199329《Linux内核原理与分析》第一周作业

    Linux学习随笔 Linux 是一个操作系统,我们的 Linux 主要是系统调用和内核那两层. UNIX前身是Multics,但 UNIX 的商业版本非常昂贵,于是Linus Torvalds(Li ...

  7. [Qt]执行cmd命令

    要加 /c 参数 QProcess p; p.start("cmd", QStringList()<<"/c"<<"ping ...

  8. Zabbix备份数据文件

    mysql自带的工具mysqldump,当数据量大了之后进行全备所花的时间比较长,这样将会造成数据库的锁读.从而zabbix服务的监控告警不断,想着做下配置文件的备份.刚好有这么个脚本.满足了需求. ...

  9. C++多线程队列实现

    C++多线程队列实现 C++多线程队列学习 介绍 在项目中,进行多线程队列实现是一个比较麻烦的事, 找到了一个实现比较好的多线程队列实现, 自己做了一点修改更加适应自己的项目, 记录下来, 有需要的自 ...

  10. IDEA 之 Java项目复制

    1.复制一个项目,并改名字  2.更改以下文件名字  3.将以下文件中的原有名字,替换成更改后的名字(例如MyWebapp07替换成MyWebapp08) 4.将out文件夹给删除 5.然后用IDEA ...