Manacher(马拉车)算法(jekyll迁移)
layout: post
title: Manacher(马拉车)算法
date: 2019-09-07
author: xiepl1997
cover: 'assets/img/manacher.png'
tags: 敲敲敲
Manacher’s Alogrithm,中文名叫马拉车算法,是一位叫Manacher的人在1975年提出的一种算法,解决的问题是求最长回文子串,算法的神奇之处就在于将时间复杂度精进到了O(N)。还记得在两年前的四省赛中,有一道关于回文的题,题解就是用马拉车算法做解的,然而我们没有做出来。
01 由来
在求解最长回文子串时,一般的思路是以当前字符为中心向两边扩展寻找回文,但复杂度是O(N^2),那能不能将复杂度降低到线性?马拉车算法就是为此诞生的。
02 预处理
为了在处理字符串的时候不需要为字符串长度是奇数还是偶数而分别考虑,将对原始字符串进行处理,在每一个字符的左右两边都加上特殊字符(肯定不存在原始字符串中的字符),让字符串变成一个长度为奇数的字符串。如: abba --> #a#b#b#a#
03 计算最长回文子串长度
以字符串"arddrb"为例,将预处理后的新字符串"#a#r#d#d#r#b#",作为一个新的字符串arr,定义一个辅助数组Len,Len的长度与arr等长,用Len[i]来表示以arr[i]字符为中心的最长回文半径。
在等待Len数组计算出来之后,取Len数组中值最大的数所对应的下标,就是arr字符串中的所对应的字符为中心的回文串的半径,Len数组有一个特点:Len[i]-1的值,就是原字符串中该以该字符为中心的回文串的长度。以下为i、arr、Len对应的值
i 0 1 2 3 4 5 6 7 8 9 10 11 12
arr # a # r # d # d # r # b #
Len 1 2 1 2 1 2 5 2 1 2 1 2 1
04 计算回文子串起始索引
取出Len数组中最大的值的索引i后,应该如何由得到原字符串该字符的索引呢?继续以str="arddrb"为例,有arr="#a#r#d#d#r#b#",Len[6]=5,发现6-Len(6)=1,即i-Len[i]就是arr[i]字符在原始字符串中的下标。但以str="aba"为例,arr="#a#b#a#",Len[3]=4,3-Len[3]=-1,所以str[-1]将会溢出。为了避免奇回文溢出,所以在arr的首尾再分别添加一个特殊字符,如下
i 0 1 2 3 4 5 6 7 8 9 10
arr @ # c # a # b # a # $
Len 1 1 2 1 2 1 4 1 2 1 1
可以看出,对于b字符来说,6-Len(6)=2,可以得到最长回文子串的起始索引为(i-Len(i))/2。
05 计算Len数组
第三步和第四部都是以Len数组计算完成为前提来进行的,计算Len数组就是马拉车算法的主要工作了,还是以"arddrb"为例,
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
arr @ # a # r # d # d # r # b # $
Len 1 1 2 1 2 1 2 5 2 1 2 1 2 1 1
定义两个变量Mi和R,Mi是所有回文子串中,能延伸到最右端位置的那个回文子串的中心点位置,R是该回文串能延伸到最右端的位置。
当i=7时,Len[i]=5,在以位置7位中心点的回文子串中,该回文串的右边界是位置12。
当i=12时,Len[i]=2,在以位置12位中心点的回文子串中,该回文串的右边界是位置14。
所以可以得到,R=Len[i]+i
具体编程时,从左往右计算数组Len,需要分以下情况
1) 当i <= R时,首先毫无疑问Len数组中i点之前的对应的值已经求出来了,利用回文的特点,只要找到i关于Mi点对称的点j,j=Mi* 2-i,i、j在以Mi为中心的回文串的范围内[L, R]:
- 如果Len[j] < R-i(同样是L到j的距离),说明以j为中心的回文串没有超出范围[L, R],所以,Len[i] = Len(j),如下图
- 如果Len[j] >= R-i,即j为中心的回文串的最左端超过L,如下图所示,所以Len[i] = Len[j]是不成立的,有回文串的特性可知,Len[i] 至少等于R-i,至于是否大于R-i,那还得需要从R+1开始一一匹配,直到失配为止,从而更新R和对应的中心点Mi以及Len[i]。
2) 当i > R时,如下图,这种情况没法用到回文串的特性,只能老实地去一一匹配。
代码如下(以leetcode第5题为例)
public String longestPalindrome(String s) {
int mi = 0;
int right = 0;
int maxlength = 0;
int maxpoint = 0;
String temp = "@#";
for(int i = 0; i < s.length(); i++){
temp += s.charAt(i);
temp += "#";
}
temp += "*";
int[] p = new int[temp.length()];
for(int i = 0; i < temp.length(); i++){
p[i] = 0;
}
for(int i = 1; i < temp.length()-1; i++){
p[i] = right > i? Math.min(p[2*mi-i], right - i) : 1;
while(temp.charAt(i+p[i]) == temp.charAt(i-p[i])){
p[i]++;
}
if(i + p[i] > right){
right = i + p[i];
mi = i;
}
if(maxlength < p[i]){
maxlength = p[i];
maxpoint = i;
}
}
//(maxpoint - maxlength)/2为最长回文数的起始点,maxlength为最长回文数的长度
return s.substring((maxpoint - maxlength)/2, (maxpoint - maxlength)/2 + maxlength - 1);
}
理解p[i] = right > i? Math.min(p[2* mi-i], right - i) : 1;
就将manacher理解的差不多了。
Manacher(马拉车)算法(jekyll迁移)的更多相关文章
- manacher(马拉车算法)
Manacher(马拉车算法) 序言 mannacher 是一种在 O(n)时间内求出最长回文串的算法 我们用暴力求解最长回文串长度的时间复杂度为O(n3) 很明显,这个时间复杂度我们接受不了,这时候 ...
- HDU - 3068 最长回文manacher马拉车算法
# a # b # b # a # 当我们遇到回判断最长回文字符串问题的时候,若果用暴力的方法来做,就是在字符串中间添加 #,然后遍历每一个字符,找到最长的回文字符串.那么马拉车算法就是在这个基础上进 ...
- Manacher (马拉车) 算法:解决最长回文子串的利器
最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...
- manacher马拉车算法
Manacher算法讲解 总有人喜欢搞事情,出字符串的题,直接卡掉了我的40分 I.适用范围 manacher算法解决的是字符串最长回文子串长度的问题. 关键词:最长 回文 子串 II.算法 1.纯暴 ...
- 最长回文子串 —— Manacher (马拉车) 算法
最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...
- Manacher(马拉车)算法
Manacher算法是一个求字符串的最长回文子串一种非常高效的方法,其时间复杂度为O(n).下面分析以下其实行原理及代码: 1.首先对字符串进行预处理 因为回文分为奇回文和偶回文,分类处理比较麻烦,所 ...
- [模板] Manacher(马拉车)算法
用途 求回文子串 做法 先考虑回文子串以某字符为中心的情况,即长度为奇数 推着做,记rad[i]为以i位置为中心的最大半径(包含中点) 考虑怎么求rad[i].找之前的一个右端点最靠右的位置p,设它的 ...
- Manacher(马拉车)算法详解
给定一个字符串,求出其最长回文子串 eg: abcba 第一步: 在字符串首尾,及各字符间各插入一个字符(前提这个字符未出现在串里). 如 原来ma /* a b a b c ...
- Manacher's Algorithm 马拉车算法
这个马拉车算法Manacher‘s Algorithm是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这 ...
随机推荐
- db2创建nickname
db2创建nickname创建步骤 1.创建 server create server servername type DB2/AIX version 10.5 wrapper drda authid ...
- 不藏了,摊牌了,一张知识图谱整理完整Java并发体系,就问全不全
推荐阅读: 2020年马士兵Java多线程高并发讲解——百万年薪架构师告诉你Java多线程与高并发 目录 这是我关于整个Java并发体系的整理,结合的主要是现在市面上对于Java并发在面试的过程中经常 ...
- 笨办法学Python 3|百度网盘免费下载|新手基础入门书籍
点击下方即可百度网盘免费提取 百度网盘免费下载:笨办法学Python 3 提取码:to27 内容简介: 本书是一本Python入门书,适合对计算机了解不多,没有学过编程,但对编程感兴趣的读者学习使用. ...
- 谁能告诉我如何通过Jenkins完成分布式环境搭建并执行自动化脚本
今天我们接着昨天的内容,看一看如何完成Jenkins分布式环境的搭建和使用,因为我之前也是自己一个人摸索的,如果有不对的地方,请各位看官私信指出. 新增分布式部署节点 在系统管理/节点管理中点击新建 ...
- 解决element上传功能清除单个文件的问题
今天,在使用 element 实现一个上传文件的功能. 接下来,要对上传的文件列表,实现删除单文件的功能. 看了 element 开发文档,发现 on-remove 没有特别的详细的说明,刚开始使用 ...
- kafka笔记——kafka启动
1. 准备 阿里云Linux服务器一个(Centos7) 腾讯云Linux服务器一个(CentOs7) zookeeper,kafka压缩包 Java环境配置好 要死....脚本之家 2. 安装 zo ...
- Android个人中心UI
参考:https://blog.csdn.net/gjm15881133824/article/details/73742219
- 3. 懂了这些,方敢在简历上说会用Jackson写JSON
你必须非常努力,才能看起来毫不费力.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众 ...
- Python简单的语句组
Python简单的语句组: ''' if 条件1: 条件1满足时,需要运行的内容 ''' num = 10 if num % 6 == 4: print("num 对 6 的取模结果是 4& ...
- Django学习路17_聚合函数(Avg平均值,Count数量,Max最大,Min最小,Sum求和)基本使用
使用方法: 类名.objects.aggregate(聚合函数名('表的列名')) 聚合函数名: Avg 平均值 Count数量 Max 最大 Min 最小 Sum 求和 示例: Student.ob ...