【算法】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算法 朴素 求一个字符串中 ...
随机推荐
- JAVA获取访问者IP地址
pom <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomc ...
- 【LeetCode】666. Path Sum IV 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS 日期 题目地址:https://leetcod ...
- 【LeetCode】108. Convert Sorted Array to Binary Search Tree 解题报告 (Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 Python解法 日期 题目地址:ht ...
- 【LeetCode】589. N-ary Tree Preorder Traversal 解题报告 (Python&C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 迭代 日期 题目地址:https://leetc ...
- 【操作系统】 DOS命令windows批处理batch编程——第一章
参考网址: http://docs.30c.org/dosbat/index.html 很多情况下,我们只需要记住一条命令 help ,就能掌握整个DOS命令.比如直接输入 help 可以得到命令的帮 ...
- HAT
目录 概 主要内容 代码 Rade R. and Moosavi-Dezfooli S. Helper-based adversarial training: reducing excessive m ...
- Xcode Error returned in reply: Connection invalid
当电脑上有Xcode两个版本是使用其中的某一个的Simulator时出现了这样的报错 在Preference->Location->Command Line Tool 选择 Xcode 9 ...
- rapidjson解析与构造实例
void rapidjson1(){ rapidjson::StringBuffer s; rapidjson::Writer<rapidjson::StringBuffer> write ...
- Drools的Eclipse_IDEA插件安装
1.说明 Drools使用时不是必须依赖插件的, 只是在安装了相应的插件之后, 在开发工具中能识别到对应的drools文件, 能够进行一些智能提示. 以及使用插件提供的便捷功能. 2.Eclipse插 ...
- Swoole 中使用 Table 内存表实现进程间共享数据
背景 在多进程模式下进程之间的内存是相互隔离的,在一个工作进程中的全局变量和超全局变量,在另一个工作进程中是无法读取和操作的. 如果只有一个工作进程,则不存在进程隔离问题,可以使用全局变量和超全局变量 ...