Manacher算法 O(n) 求最长回文子串
本文转自:http://bbs.dlut.edu.cn/bbstcon.php?board=Competition&gid=23474
首先:大家都知道什么叫回文串吧,这个算法要解决的就是一个字符串中最长的回文子串有多长。这个算法可以在O(n)的时间复杂度内既线性时间复杂度的情况下,求出以每个字符为中心的最长回文有多长,
这个算法有一个很巧妙的地方,它把奇数的回文串和偶数的回文串统一起来考虑了。这一点一直是在做回文串问题中时比较烦的地方。这个算法还有一个很好的地方就是充分利用了字符匹配的特殊性,避免了大量不必要的重复匹配。
算法大致过程是这样。先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子,回文串长度全为奇数了),然后用一个辅助数组P记录以每个字符为中心的最长回文串的信息。P[id]记录的是以字符str[id]为中心的最长回文串,当以str[id]为第一个字符,这个最长回文串向右延伸了P[id]个字符(包含str[id]在内的P[id]个字符)。
原串: w aa bwsw f d
新串: # w # a # a # b # w # s # w # f # d #
辅助数组P: 1 2 1 2 3 2 1 2 1 2 1 4 1 2 1 2 1 2 1
这里有一个很好的性质,P[id]-1就是该回文子串在原串中的长度(不包括‘#’)。如果这里不是特别清楚,可以自己拿出纸来画一画,自己体会体会。当然这里可能每个人写法不尽相同,不过我想大致思路应该是一样的吧。
好,我们继续。现在的关键问题就在于怎么在O(n)时间复杂度内求出P数组了。只要把这个P数组求出来,最长回文子串就可以直接扫一遍得出来了。
由于这个算法是线性从前往后扫的。那么当我们准备求P[i]的时候,i以前的P[j]我们是已经得到了的。我们用mx记在i之前的回文串中,延伸至最右端的位置。同时用id这个变量记下取得这个最优mx时的id值。(注:为了防止字符比较的时候越界,我在这个加了‘#’的字符串之前还加了另一个特殊字符‘$’,故我的新串下标是从1开始的)
好,到这里,我们可以先贴一份代码了。
void pk()
{
int i;
int mx = ;
int id;
for(i=; i<n; i++)
{
if( mx > i )
p[i] = MIN( p[*id-i], mx-i );
else
p[i] = ;
for(; str[i+p[i]] == str[i-p[i]]; p[i]++)
;
if( p[i] + i > mx )
{
mx = p[i] + i;
id = i;
}
}
}
代码是不是很短啊,而且相当好写。很方便吧,还记得我上面说的这个算法避免了很多不必要的重复匹配吧。这是什么意思呢,其实这就是一句代码。
if( mx > i )
p[i] = MIN( p[2*id-i], mx-i );
就是当前面比较的最远长度mx>i的时候,P[i]有一个最小值。这个算法的核心思想就在这里,为什么P数组满足这样一个性质呢?
(下面的部分为图片形式)
两个基本题:hdu 3068 poj 3974
#include<cstdio>
#include<cstring>
const int M = *;
char str[M];//start from index 1
int p[M];
char s[M];
int n;
void checkmax(int &ans,int b){
if(b>ans) ans=b;
}
inline int min(int a,int b){
return a<b?a:b;
}
void kp(){
int i;
int mx = ;
int id;
for(i=; i<n; i++){
if( mx > i )
p[i] = min( p[*id-i], p[id]+id-i );
else
p[i] = ;
for(; str[i+p[i]] == str[i-p[i]]; p[i]++) ;
if( p[i] + i > mx ) {
mx = p[i] + i;
id = i;
}
}
}
void pre()
{
int i,j,k;
n = strlen(s);
str[] = '$';
str[] = '#';
for(i=;i<n;i++)
{
str[i* + ] = s[i];
str[i* + ] = '#';
}
n = n* + ;
str[n] = ;
} void pt()
{
int i;
int ans = ;
for(i=;i<n;i++)
checkmax(ans, p[i]);
printf("%d\n", ans-);
} int main()
{
int T,_=;
while( scanf("%s", s) !=EOF )
{
pre();
kp();
pt();
}
return ;
}
Manacher算法 O(n) 求最长回文子串的更多相关文章
- [算法] Manacher算法线性复杂度内求解最长回文子串
参考:http://www.felix021.com/blog/read.php?2040 以上参考的原文写得很好,解析的非常清楚.以下用我自己的理解,对关键部分算法进行简单的描述: 回文的判断需要完 ...
- PAT甲题题解-1040. Longest Symmetric String (25)-求最长回文子串
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789177.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- Manacher模板( 线性求最长回文子串 )
模板 #include<stdio.h> #include<string.h> #include<algorithm> #include<map> us ...
- hdu 3068 最长回文(manachar求最长回文子串)
题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...
- Manacher算法——求最长回文子串
首先,得先了解什么是回文串.回文串就是正反读起来就是一样的,如“abcdcba”.我们要是直接采用暴力方法来查找最长回文子串,时间复杂度为O(n^3),好一点的方法是枚举每一个字符,比较较它左右距离相 ...
- manacher算法求最长回文子串
一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abcc ...
- Manacher 求最长回文子串算法
Manacher算法,是由一个叫Manacher的人在1975年发明的,可以在$O(n)$的时间复杂度里求出一个字符串中的最长回文子串. 例如这两个回文串“level”.“noon”,Manacher ...
- Manacher算法(马拉车)求最长回文子串
Manacher算法求最长回文字串 算法思路 按照惯例((・◇・)?),这里只是对算法的一些大体思路做一个描述,因为找到了相当好理解的博客可以参考(算法细节见参考文章). 一般而言,我们的判断回文算法 ...
- [hdu3068 最长回文]Manacher算法,O(N)求最长回文子串
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文 ...
随机推荐
- ORACLE-用户常用数据字典的查询使用方法
一.用户 查看当前用户的缺省表空间 SQL> select username,default_tablespace from user_users; USERNAME DEFAULT_TABLE ...
- GIS中栅格数据的拼接
Datamanager Tools——Raster——Raster Dataset——Mosaic to New Raster 如果最大值是实际的真值,选择masaic operator要保留Max ...
- Union-SQL Server学习笔记
1.简单笔记 数据库查询语句中,通过UNION组合查询语句,可以将两个或更多查询的结果组合为单个结果集,该结果集包含组合查询中的所有查询的全部行. 利用UNION语句可以实现将不同数据表中符合条件,不 ...
- jQuery选项卡插件
html结构 <ul id="tabs" class="tabs"> <li data-tab="users">Us ...
- http压力测试
一.http_load程序非常小,解压后也不到100Khttp_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把 ...
- iOS-添加测试设备Identifier
第一步:确认你的设备已经连接 第二步:点击xcode上"Windows"标签,选择"Devices" 第三步:在弹出的左框选择你要添加的设备.在右边框里可以找到 ...
- [转]p2p端口映射工具 dog-tunnel
[转]p2p端口映射工具 dog-tunnel http://www.oschina.net/p/dog-tunnel 狗洞是一个高速的 P2P 端口映射工具,同时支持Socks5代理. 0.5版后开 ...
- UIScrowView swift
// // ViewController.swift // UILabelTest // // Created by mac on 15/6/23. // Copyright (c) 2015年 fa ...
- tcp传输黏包
tcp传输黏包 tcpip协议使用"流式"(套接字)进行数据的传输,就是说它保证数据的可达以及数据抵达的顺序,但并不保证数据是否在你接收的时候就到达,特别是为了提高效率,充分利用带 ...
- MSSQL Transaction[事务] and Procedure[存储过程]
--事务分三种 --1.显示事务 --我们手动begin transaction ...... commit transaction/rollback transaction --上面这种写法叫做“显 ...