【算法】Manacher算法
最长回文串问题
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算法的更多相关文章
- 经典算法 Manacher算法详解
内容: 1.原始问题 =>O(N^2) 2.Manacher算法 =>O(N) 1.原始问题 Manacher算法是由题目“求字符串中长回文子串的长度”而来.比如 abcdcb 的 ...
- [转]O(n)回文子串算法 Manacher算法
这里,我介绍一下O(n)回文串处理的一种方法.Manacher算法.原文地址:http://zhuhongcheng.wordpress.com/2009/08/02/a-simple-linear- ...
- [算法] Manacher算法线性复杂度内求解最长回文子串
参考:http://www.felix021.com/blog/read.php?2040 以上参考的原文写得很好,解析的非常清楚.以下用我自己的理解,对关键部分算法进行简单的描述: 回文的判断需要完 ...
- 浅谈Manacher算法与扩展KMP之间的联系
首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解.网上解法颇多.时间复杂度也不尽同样,这里列述几种常见的解法. 解法一 ...
- ACM -- 算法小结(八)字符串算法之Manacher算法
字符串算法 -- Manacher算法 首先介绍基础入门知识,以下这部分来着一贴吧,由于是很久之前看的,最近才整理一下,发现没有保存链接,请原创楼主见谅. //首先:大家都知道什么叫回文串吧,这个算法 ...
- Manacher算法总结
部分图片转自:http://www.cnblogs.com/grandyang/p/4475985.html manacher算法(民间称马拉车算法233)是用来找字符串中的最长回文子串的,先来说一下 ...
- 最长回文子串(动规,中心扩散法,Manacher算法)
题目 leetcode:5. Longest Palindromic Substring 解法 动态规划 时间复杂度\(O(n^2)\),空间复杂度\(O(n^2)\) 基本解法直接看代码 class ...
- [hdu3068 最长回文]Manacher算法,O(N)求最长回文子串
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文 ...
- 使用manacher算法解决最长回文子串问题
要解决的问题 求一个字符串最长回文子串是什么.且时间复杂度 O(N) 具体描述可参考: LeetCode_5_最长回文子串 LintCode_200_最长回文子串 暴力解法 以每个字符为中心向左右两边 ...
- Manacher算法讲解——字符串最长回文子串
引 入 引入 引入 Manachar算法主要是处理字符串中关于回文串的问题的,这没什么好说的. M a n a c h e r 算 法 Manacher算法 Manacher算法 朴素 求一个字符串中 ...
随机推荐
- LuoguP7478 【A】StickSuger 题解
Content 给定一个长度为 \(n\) 的仅包含小写字母的字符串 \(s\),请找到一个二元组 \((i,j)\)(\(i<j\))使得在交换字符串 \(s\) 的第 \(i\) 个和第 \ ...
- CF721B Passwords 题解
Content 有一天,小 V 突然忘记了他在 Codehorses 的网站上的密码.但是他有所有网站上的 \(n\) 个密码 \(\{s_i\}_{i=1}^n\),所以他开始一个一个试.他会先从长 ...
- dump Java 程序和服务器相关信息
#!/bin/bash jps -lm read -p "enter java pid: " pid port=$(netstat -ntlp | grep $pid | awk ...
- java 常用类库:格式化NumberFormat;SimpleDataFormat类(转换Data()对象);DateTimeFormatter 转换LocalDateTime时间对象
NumberFormat类 该类是一个做数字格式化的类,它是一个抽象类,无法实例化.它提供了parse()和format()方法,其中format用于将数值,格式转化成字符串,parse()用于把字符 ...
- 实体转为json的,如何处理外键情况
实体转为json的,如何处理外键情况 jc.registerJsonValueProcessor(Userrelation.class, new JsonValueProcessor() {// 此处 ...
- 『学了就忘』Linux日志管理 — 90、Linux中日志介绍
目录 1.日志相关服务 2.系统中常见的日志文件 1.日志相关服务 在CentOS 6.x中日志服务已经由rsyslogd取代了原先的syslogd服务.RedHat认为syslogd已经不能满足在工 ...
- C printf 字符串格式化
%a 浮点数.十六进制数字和p-记数法(C99) %A 浮点数.十六进制数字和p-记法(C99) %c 一个字符 %d 有符号十进制整数 %e 浮点数.e-记数法 %E 浮点数.E-记数法 %f 浮点 ...
- 【LeetCode】477. Total Hamming Distance 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 位运算 日期 题目地址:https://leetco ...
- 【LeetCode】503. Next Greater Element II 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力解法 单调递减栈 日期 题目地址:https:/ ...
- CS5218替代AG6310方案|设计DP转HDMI转换方案|替代AG6310方案
AG6310是一款实现显示端DP口转HDMI数据转换器.AG6310是一款单芯片解决方案,通过DP端口连接器传输视频和音频流,其DP1.2支持可配置的1.2和4通道,分别为1.62Gbps.2.7Gb ...