原文转载自:http://blog.csdn.net/lsjseu/article/details/9990539

偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙。Stupid。

题目描述:

回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。

回文子串,顾名思义,即字符串中满足回文性质的子串。

给出一个只由小写英文字符a,b,c…x,y,z组成的字符串,请输出其中最长的回文子串的长度。

输入:

输入包含多个测试用例,每组测试用例输入一行由小写英文字符a,b,c…x,y,z组成的字符串,字符串的长度不大于200000。

输出:

对于每组测试用例,输出一个整数,表示该组测试用例的字符串中所包含的的最长回文子串的长度。

样例输入:

abab
bbbb
abba

样例输出:

3
4
4

思路:

回文串包括奇数长的和偶数长的,一般求的时候都要分情况讨论,这个算法做了个简单的处理把奇偶情况统一了。原来是奇数长度还是奇数长度,偶数长度还是偶数长度。

算法的基本思路是这样的,把原串每个字符中间用一个串中没出现过的字符分隔#开来(统一奇偶),同时为了防止越界,在字符串的首部也加入一个特殊符$,但是与分隔符不同。同时字符串的末尾也加入’\0’.

算法的核心:用辅助数组p记录以每个字符为核心的最长回文字符串半径。也就是p[i]记录了以str[i]为中心的最长回文字符串半径。p[i]最小为1,此时回文字符串就是字符串本身。

  先看个例子:

  原串:        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

首先看代码(借助http://blog.csdn.net/thyftguhfyguj/article/details/9531149):

 #include <stdio.h>
#include <iostream>
using namespace std; char s[200002];
char str[400010];
int p[400010]; int min(int a,int b){
return a < b ? a : b;
} int pre(){
int i,j = 0;
str[j++] = '$';//加入字符串首部的字符串
for(i = 0;s[i];i++){
str[j++] = '#'; //分隔符
str[j++] = s[i];
}
str[j++] = '#';
str[j] = '\0'; //尾部加'\0'
cout<<str<<endl;
return j;
} void manacher(int n){
int mx = 0,id,i;
p[0] = 0;
for(i = 1;i < n;i++){
if(mx > i) //在这个之类可以借助前面算的一部分
p[i] = min(mx - i,p[2 * id - i]); //p[2*id-i]表示j处的回文长度
else //如果i大于mx,则必须重新自己算
p[i] = 1;
while(str[i - p[i]] == str[i + p[i]]) //算出回文字符串的半径
p[i]++;
if(p[i] + i > mx){ //记录目前回文字符串扩展最长的id
mx = p[i] + i;
id = i;
}
}
} int main(int argc, char const *argv[]){ while(scanf("%s",s) != EOF){
int n = pre();
manacher(n);
int ans = 0,i;
for(i = 1;i < n;i++)
if(p[i] > ans)
ans = p[i];
printf("%d\n",ans - 1);
}
return 0;
}

上面的程序说明:pre()函数对给定字符串进行预处理,也就是加分隔符。

上面几个变量说明:id记录具有遍历过程中最长半径的回文字符串中心字符串。mx记录了具有最长回文字符串的右边界。看下面这个图(注意,j为i关于id对称的点,j = 2*id - i):

但是p[i] = p[j]是没有错的,但是这里有个问题,就是i的一部分超出阴影部分,这就不对了。请看下图(为了看得更清楚,下面子串用细条纹表示):

此时,根据对称型只能得出p[i]和p[j]红色阴影部分是相等的,这就为什么有取最小值这个操作:

   if(mx > i)  //在这个之类可以借助前面算的一部分
p[i] = min(mx - i,p[2 * id - i]);

下面代码就很容易看懂了。

最后遍历一遍p数组,找出最大的p[i]-1就是所求的最长回文字符串长度,下面证明一下:

(1)因为p[i]记录插入分隔符之后的回文字符串半径,注意插入分隔符之后的字符串中的回文字符串肯定是奇数长度,所以以i为中心的回文字符串长度为2*p[i]-1。

例如:

bb=>#b#b#
bab=>#b#a#a#b#

2)注意上面两个例子的关系。#b#b#减去一个#号的长度就是原来的2倍。即((2*p[i]-1)-1)/2 = p(i)-1,得证。

算法的有效比较次数为MaxId 次,所以说这个算法的时间复杂度为O(n)。

【转载】最长回文字符串(manacher算法)的更多相关文章

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

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

  2. 第5题 查找字符串中的最长回文字符串---Manacher算法

    转载:https://www.felix021.com/blog/read.php?2040 首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一 ...

  3. 九度OJ 1528 最长回文子串 -- Manacher算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...

  4. lintcode最长回文子串(Manacher算法)

    题目来自lintcode, 链接:http://www.lintcode.com/zh-cn/problem/longest-palindromic-substring/ 最长回文子串 给出一个字符串 ...

  5. 最长回文子串—Manacher 算法 及 python实现

    最长回文子串问题:给定一个字符串,求它的最长回文子串长度.如果一个字符串正着读和反着读是一样的,那它就是回文串.   给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最 ...

  6. hihocoder #1032 : 最长回文子串 Manacher算法

    题目链接: https://hihocoder.com/problemset/problem/1032?sid=868170 最长回文子串 时间限制:1000ms内存限制:64MB 问题描述 小Hi和 ...

  7. 5. Longest Palindromic Substring(最长回文子串 manacher 算法/ DP动态规划)

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  8. hihoCoder #1032 : 最长回文子串 [ Manacher算法--O(n)回文子串算法 ]

    传送门 #1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相 ...

  9. HDU 3068:最长回文(Manacher算法)

    http://acm.hdu.edu.cn/showproblem.php?pid=3068 最长回文 Problem Description   给出一个只由小写英文字符a,b,c...y,z组成的 ...

随机推荐

  1. Day7下

    T1 我直接就用的LCA ,可能慢点.反正数据试过了. T2 期望dp不会啊. T3 好麻烦.

  2. 收藏 创建第一个mvc

    http://blog.csdn.net/sdtsfhh/article/details/8201956

  3. Windows环境下sublime text 3搭建前端开发环境

    一.安装SubLime Text 3 SubLime Text 3官网下载:https://www.sublimetext.com/ 二.安装Package Control 进入sublime后,按快 ...

  4. spring笔记2-注解

    一.属性与成员变量的区别: 属性:对外暴露的,getxxx/setxxx称为属性; 成员变量:private String name称为成员变量或字段 二.applicationContext.xml ...

  5. 栅格那点儿事(四E)

    栅格金字塔   如果上面的部分都已经看过了,那么如何在ArcMap中更好的渲染一个栅格数据你已经知道了.可仅展示好一个栅格数据是不够的,我们还需要知道如何快速的展示一个栅格数据. 讲金字塔之前,先解释 ...

  6. java实现一个简单的数学表达式分析器(加减乘除和括号)

    1.使用此分析器需要输入两个量: String str1=运算符号有前后有空格的数学表达式(如 1 + 2 *  ( 3+1)  - 5 #),并在最后添加‘#’字符作为结束标志: String st ...

  7. iphone 微信下浏览器中数字去除下划线

    在开发iphone应用程序的时候,safari下手机号码默认是有下划线的,通过下面的方法就可以去掉: <meta name="format-detection" conten ...

  8. linux下搭建svn并同步更新至web目录

    安装svn 使用yum安装 yum install subversion -y 安装成功后查看版本库 svnserve  --version 生成目录 cd /var mkdir svn cd svn ...

  9. JavaScript 获取数组的最大值和最小值

    js获取数组最大值和最小值 使用apply方法: var a = [1,2,3,5]; console.log(Math.max.apply(null, a));//最大值 console.log(M ...

  10. Redis 基础概念和命令

    Redis 是什么 Redis是一种基于键值对(key-value)的NoSQL数据库. 为什么使用Redis 速度快 Redis的时间颗粒度一般是微秒,慢查询的默认值是10 000微秒,即10毫秒. ...