最长回文串问题

manacher算法是用来求解最长回文串的问题。最长回文串的解法一般有暴力法、动态规划、中心扩展法和manacher算法。

  • 暴力法的时间复杂度为\(O(n^3)\),一般都会超时;
  • 动态规划的时间复杂度和空间复杂度均为\(O(n^2)\),通过矩阵压缩存储,空间复杂度常数可以降低为0.5,但时间复杂度较高,基本不能再优化;
  • 中心扩展法在性能上优于动态规划,空间复杂度为\(O(1)\),但时间复杂度仍然是\(O(n^2)\);
  • manacher性能最好,时间复杂度和空间复杂度均为\(O(n)\)

对中心扩展法的分析

//中心扩展法的代码
class Solution {
public:
string longestPalindrome(string s) {
if(s.size() == 0)return "";
int maxlen = 1, start = 0;
for(int i = 0; i < s.size(); ++i){
int len1 = expand(s, i, i);
int len2 = expand(s, i, i + 1);
int len = max(len1, len2);
if(len > maxlen){
start = i - (len - 1) / 2;
maxlen = len;
}
}
return s.substr(start, maxlen);
}
private : int expand(const string &s, int l, int r){
while(l >= 0 && r < s.size() && s[l] == s[r]){
l--;
r++;
}
return r - l - 1;
}
};

中心扩展法造成时间复杂度高的原因主要有两个方面:

  • 需要分奇数和偶数两种情况讨论;
  • 子串包含重复计算;

第一点从代码可以看出,第二点见插图:



对第 \(j\)个字符进行中心扩展时, 子串\(s[0, j - 1]\)都已经进行了中心扩展,以每个字符为中心的回文串信息都已经获得,在这些回文串中必然存在一个最长的回文串\(s[mx, my]\),其对称中心记作\(id\)。如果\(j < my\),则\(j\)一定有一个对称位置\(i\),假设以\(i\)为中心的回文串为左侧绿色的子串,则以\(j\)为中心的绿色子串一定也是回文串。但是中心扩展法忽略了这点,对这部分子串进行了重复比对。

manacher算法思想

manacher算法主要是对中心扩展法的两方面不足进行改进。

字符串预处理

为了不区分奇数和偶数两种情况,manacher对字符串进行了预处理,在长度为\(n\)的字符串的空隙中填入\(n+1\)相同的字符,使字符串的总长度变为\(2n + 1\)。

例如:

对于字符串abbac,处理之后为#a#b#b#a#c#(假设插入的字符为#

处理之后的字符串与原字符串的映射关系为:\(s[i] = temps[2 * i + 1]\)

\(i\)号位置之前有 \(i+1\)个gap

处理后的最大回文串长度与原来的长度的关系:\((tempLmax - 1) / 2 = lmax\)

算法实现

  • 数据结构

    • 回文半径数组\(radius[len]\)

      \(radius[i] = (tempLmax(i) - 1) / 2\),含义为字符\(temps[i]\)右侧的字符个数(不懂网上很多版本为什么带上\(temps[i]\))

    • 最大覆盖范围\((id, mx)\),\(id\)为对称中心

  • 算法实现

    • 每次在进行中心扩展时,先计算一个合适的扩展起点,而不是直接从当前位置直接扩展
    • 扩展的方法同中心扩展法相同
    • 每次扩展完毕,要更新最大覆盖范围\((id, mx)\)和最大长度

代码

string longestPalindrome(string s) {
if(s.size() == 0)return "";
string temps = "#";
for(int i = 0; i < s.size(); ++i){
temps += s[i];
temps += '#';
}
int len = temps.size();
int radius[len] = {0};
int id = 0, mx = 0;
int start = 0, maxlen = 0;
for(int i = 1; i < len; ++i){
if(i < mx){
radius[i] = min(radius[2 * id - i], mx - i);
}
for(int dl = radius[i] + 1; i - dl >= 0 && i + dl < len; ++dl){
if(temps[i - dl] == temps[i + dl])radius[i]++;
else break;
}
if(radius[i] + i > mx){
id = i;
mx = radius[i] + i;
}
if(radius[i] > maxlen){
start = (i - radius[i]) / 2;
maxlen = radius[i];
}
}
return s.substr(start, maxlen);
}

更详细的的介绍

【算法】Manacher算法的更多相关文章

  1. 经典算法 Manacher算法详解

    内容: 1.原始问题   =>O(N^2) 2.Manacher算法   =>O(N) 1.原始问题 Manacher算法是由题目“求字符串中长回文子串的长度”而来.比如 abcdcb 的 ...

  2. [转]O(n)回文子串算法 Manacher算法

    这里,我介绍一下O(n)回文串处理的一种方法.Manacher算法.原文地址:http://zhuhongcheng.wordpress.com/2009/08/02/a-simple-linear- ...

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

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

  4. 浅谈Manacher算法与扩展KMP之间的联系

    首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解.网上解法颇多.时间复杂度也不尽同样,这里列述几种常见的解法. 解法一   ...

  5. ACM -- 算法小结(八)字符串算法之Manacher算法

    字符串算法 -- Manacher算法 首先介绍基础入门知识,以下这部分来着一贴吧,由于是很久之前看的,最近才整理一下,发现没有保存链接,请原创楼主见谅. //首先:大家都知道什么叫回文串吧,这个算法 ...

  6. Manacher算法总结

    部分图片转自:http://www.cnblogs.com/grandyang/p/4475985.html manacher算法(民间称马拉车算法233)是用来找字符串中的最长回文子串的,先来说一下 ...

  7. 最长回文子串(动规,中心扩散法,Manacher算法)

    题目 leetcode:5. Longest Palindromic Substring 解法 动态规划 时间复杂度\(O(n^2)\),空间复杂度\(O(n^2)\) 基本解法直接看代码 class ...

  8. [hdu3068 最长回文]Manacher算法,O(N)求最长回文子串

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文 ...

  9. 使用manacher算法解决最长回文子串问题

    要解决的问题 求一个字符串最长回文子串是什么.且时间复杂度 O(N) 具体描述可参考: LeetCode_5_最长回文子串 LintCode_200_最长回文子串 暴力解法 以每个字符为中心向左右两边 ...

  10. Manacher算法讲解——字符串最长回文子串

    引 入 引入 引入 Manachar算法主要是处理字符串中关于回文串的问题的,这没什么好说的. M a n a c h e r 算 法 Manacher算法 Manacher算法 朴素 求一个字符串中 ...

随机推荐

  1. LuoguP7478 【A】StickSuger 题解

    Content 给定一个长度为 \(n\) 的仅包含小写字母的字符串 \(s\),请找到一个二元组 \((i,j)\)(\(i<j\))使得在交换字符串 \(s\) 的第 \(i\) 个和第 \ ...

  2. CF721B Passwords 题解

    Content 有一天,小 V 突然忘记了他在 Codehorses 的网站上的密码.但是他有所有网站上的 \(n\) 个密码 \(\{s_i\}_{i=1}^n\),所以他开始一个一个试.他会先从长 ...

  3. dump Java 程序和服务器相关信息

    #!/bin/bash jps -lm read -p "enter java pid: " pid port=$(netstat -ntlp | grep $pid | awk ...

  4. java 常用类库:格式化NumberFormat;SimpleDataFormat类(转换Data()对象);DateTimeFormatter 转换LocalDateTime时间对象

    NumberFormat类 该类是一个做数字格式化的类,它是一个抽象类,无法实例化.它提供了parse()和format()方法,其中format用于将数值,格式转化成字符串,parse()用于把字符 ...

  5. 实体转为json的,如何处理外键情况

    实体转为json的,如何处理外键情况 jc.registerJsonValueProcessor(Userrelation.class, new JsonValueProcessor() {// 此处 ...

  6. 『学了就忘』Linux日志管理 — 90、Linux中日志介绍

    目录 1.日志相关服务 2.系统中常见的日志文件 1.日志相关服务 在CentOS 6.x中日志服务已经由rsyslogd取代了原先的syslogd服务.RedHat认为syslogd已经不能满足在工 ...

  7. C printf 字符串格式化

    %a 浮点数.十六进制数字和p-记数法(C99) %A 浮点数.十六进制数字和p-记法(C99) %c 一个字符 %d 有符号十进制整数 %e 浮点数.e-记数法 %E 浮点数.E-记数法 %f 浮点 ...

  8. 【LeetCode】477. Total Hamming Distance 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 位运算 日期 题目地址:https://leetco ...

  9. 【LeetCode】503. Next Greater Element II 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力解法 单调递减栈 日期 题目地址:https:/ ...

  10. CS5218替代AG6310方案|设计DP转HDMI转换方案|替代AG6310方案

    AG6310是一款实现显示端DP口转HDMI数据转换器.AG6310是一款单芯片解决方案,通过DP端口连接器传输视频和音频流,其DP1.2支持可配置的1.2和4通道,分别为1.62Gbps.2.7Gb ...