Manacher(马拉车)算法
Manacher算法是一个求字符串的最长回文子串一种非常高效的方法,其时间复杂度为O(n)。下面分析以下其实行原理及代码:
1.首先对字符串进行预处理
因为回文分为奇回文和偶回文,分类处理比较麻烦,所以我们先要做一个预处理,在字符之间插入一个特殊字符(注意这个新插入的字符不能再原字符串中出现),这样无论原字符串是奇是偶,我们将它统一的转化为奇串。初此之外,我们还需在最开头也加一个特殊字符为了防止越界,例如:
原字符串 s =” abbaTNTabcba ” ,则经过转化后这个字符串会转变为:
sNew= “$#a#b#b#a#T#N#T#a#b#c#b#a#”
2.引入一个和处理过后长=长度相同的数组记录
引入一个数组假设计为p[snew.length()],其中 p[i] 表示以snew[i]为中心,半径为p[i]的最长回文子串,p[i]=1 则表示该回文子串就是senw[i]本身,下面是snew的最长回文子串半径:
由上图可知,snew[20]='c' 为中心的最长回文子串半径为6,由于第一个和最后一个字符都是#号,且也需要搜索回文,为了防止越界,由于字符串在结尾有’\0’,所以在字符串开头需要加上非#号字符(为了区分这里用的$)。通过p数组可以找到最大回文子串半径的最大值及其中心位置,就能确定最长回文子串了。所以现在问题转化为求p数组。
3.p数组(最长回文子串半径数组)的求法
Manacher算法利用开头提到的回文的左边是右边的镜像,让回文串起始的对比位置尽可能的大:
这里引入了两个新的变量id和mx,id为最大回文串中心的位置,mx为最大回文串的右边界,i为当前遍历带字符串的为位置。
这里分两种讨论:
一、mx > i
假设当前遍历到字符串的位置i,由于在遍历到id位置的时候已知最大回文子串,位置i还在上一个最大回文子串的范围内,所以可以利用其镜像认为,位置i以id为中心镜像到另一边的位置j是对等的。 在mx>i的条件下,又分为以下两种情况:
<1.mx - i > p[j] (图1)
此时,以j为中心的回文子串包含在以id为中心的回文子串内,由于i和j位置对等,所以以i为中心的回文子串包含在以id为中心的回文子串内,所以p[i] = p[j] = p[2 * id - i]。
<2. mx - i <= p[j] (图2)
此时,以j为中心的回文子串超过了以id为中心的回文子串边界,但是由于i和j位置对等,绿框部分还是相同的。所以其向右延伸的范围最大就是mx-i,剩下超过的部分谁也不能保证是否一致,只能通过循环对比判断,所以p[i] = mx - i。
二、mx < i
此时镜像位置对预判位置起不到作用,只能从长度为1进行对比,所以此时p[i]=1;
下面为实现代码:
#include<string>
#include <vector>
#include<iostream>
#include <algorithm>
using namespace std;
string Manacher(string s)
{
string snew="$#"; //预处理,只要在原字符串中不可能出现即可
int len=s.length();
for (int i=0;i<len;i++)
{
snew+=s[i];
snew+="#";
}
int len2=snew.length();
int lenans=-1; // 最长回文子串的长度
int pos=-1; // 最长回文子串中心点的位置
vector<int> p(len2, 0);
int id=0; //当前中心点的位置
int mx=0; //最大回文子串的右边界
for (int i=1;i<len2;i++)
{
if (i<mx)
p[i]=min(p[2*id-i],mx-i);
else
p[i]=1;
while(snew[i-p[i]]==snew[i+p[i]]) //最左边sNew[0]='$',最右边sNew[sNew.size()] = '\0',无需判断边界
p[i]++;
if(p[i]+i>mx)
//我们每走一步i,都要和mx比较,我们希望mx尽可能的远,这样才能更有机会执行if(i<mx)这句代码,从而提高效率
{
id=i;
mx=i+p[i];
}
if (p[i]-1>lenans)
{
lenans=p[i]-1;
pos=i;
}
}
string::iterator iStart=s.begin()+(pos-lenans-1)/2;
//将最长回文子串起始位置转换回原串
return string(iStart,iStart+lenans);
//也可以return lenans,最长回文子串的长度
}
int main()
{
string s;
cin >> s;
cout << s << " 的最长回文子串为: " << Manacher(s) << endl;
return 0;
}
Manacher(马拉车)算法的更多相关文章
- Manacher(马拉车)算法(jekyll迁移)
layout: post title: Manacher(马拉车)算法 date: 2019-09-07 author: xiepl1997 cover: 'assets/img/manacher.p ...
- 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(马拉车)算法
用途 求回文子串 做法 先考虑回文子串以某字符为中心的情况,即长度为奇数 推着做,记rad[i]为以i位置为中心的最大半径(包含中点) 考虑怎么求rad[i].找之前的一个右端点最靠右的位置p,设它的 ...
- Manacher(马拉车)算法详解
给定一个字符串,求出其最长回文子串 eg: abcba 第一步: 在字符串首尾,及各字符间各插入一个字符(前提这个字符未出现在串里). 如 原来ma /* a b a b c ...
- Manacher's Algorithm 马拉车算法
这个马拉车算法Manacher‘s Algorithm是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这 ...
随机推荐
- Postman 设置token为全局变量
在做接口测试的时候,经常会用到不同用户登陆的token,来测试API,通过设置全局的token,这样更便捷: 注意设置的名称必须与你登陆后返回的名称一致,我这里是 AccessToken 1.配置环境 ...
- vtk学习记录(一)——vtk工程配置与生成
前言 图形图像这块儿,最近因为工作需要接触的相对多了点儿,精力基本上也都投入了这块儿,搞的天天要死要活,毕竟我一个.net的突然来到cxx的世界,也是很苦恼的,也是头一次见到新建工程就需要配置并且解决 ...
- scp--linux命令
不同服务器之间传输文件, 第一种方式: scp TC_20171230_RCE_15_37_34_build-20.tar.gz test@192.168.18.90://data/build/ 缺点 ...
- 【转】Vue.js 2.0 快速上手精华梳理
Vue.js 2.0 快速上手精华梳理 Sandy 发掘代码技巧:公众号:daimajiqiao 自从Vue2.0发布后,Vue就成了前端领域的热门话题,github也突破了三万的star,那么对于新 ...
- cs/bs
c(客户端)/s服务器:使用前必须安装,更新是,c s同时更新,不能跨频繁太,采用自由协议,相对来说安全. b(浏览器)/s:本质上还是cs ,只是使用了浏览器:如京东,淘宝.无需安装,客户端不需要更 ...
- Redis注册成服务
注册服务 redis-server.exe –-service-install redis.windows.conf 删除服务 redis-server –-service-uninstall 开启服 ...
- 树莓派raspbian安装matchbox-keyboard虚拟键盘
环境:raspbian-stretch(2018-06-27) 树莓派:3代B型 官网安装地址:http://ozzmaker.com/virtual-keyboard-for-the-raspber ...
- Abaqus 子模型法 和 子结构法
目录 1 子模型法 1.2 子模型法应用考虑因素 1.3 子模型法关键技术 1.3.1 单元选择 1.3.2 驱动变量 1.3.3 链接整体模型和子模型 1.4 仿真过程 1.4.1 问题描述 1.4 ...
- Android学习07
自定义Dialog 创建一个Java类CustomDialog继承Dialog. package com.example.helloworld.widget; import android.app.D ...
- rsync+inotify实现主机之间目录实时同步
原理: rsync:用于跨主机目录同步 inotify:用于监测目录变化 再编写一个触发脚本,一旦inotify检测到目录中内容发生变化,则调用rsync执行同步. rsync服务器的的配置: 因为r ...