Manacher

一、背景

1975年,Manacher发明了Manacher算法(中文名:马拉车算法),是一个可以在O(n)的复杂度中返回字符串s中最长回文子串长度的算法,十分巧妙。

让我们举个栗子,栗子:

1.字符串:abbababa        最长回文子串:5(abbababa

2.字符串:abcbbabbc      最长回文子串:7(abcbbabbc

3.字符串:abccbaba        最长回文子串:6(abccbaba)

传统方法是,遍历每个字符,以该字符为中心向两边查找。时间复杂度为O(n^2),效率很差;

而这个神奇的Manacher算法将复杂度提升到了O(n)。

来一起瞅一瞅它是如何工作的吧。

二、算法过程分析

回文分为奇回文(ababa)和偶回文(abba),这里比较难以处理,我们使用一个(sao)(cao)(zuo)(很重要)。我们将字符串首尾和每个字符间插入一个字符(注意:这个自符在串中并未出现)例如:'#'.

栗子!栗子!s='abbadcacda'先转化成s_new='$#a#b#b#a#d#c#a#c#d#a#\0'('$'与'\0',是边界,下面的代码中可以看到)

这样原串中的偶回文(abba)与奇回文(adcacda),变成了(#a#d#d#a#)与(#a#d#c#a#c#d#a#)两个奇回文

定义数组p[],用p[i]表示以i为中心的最长回文半径。栗子在这里:

那,p[i]该如何求呢?很显然,p[i]-1正好就是原字符中的最长回文串长度了。

让我们一起找到正解。

请看下图:

定义两个变量mx和id。mx就是以id为中心的最长回文右边界,也就是mx=id+p[id],随后我们需要mx做出它的最大贡献。

假设我们在求p[i](以i为中心的最长回文半径),如果i<mx(如上图),那么我们就用mx和j来更新到我们已知的可以更新的最大长度,代码如下:

if(i<mx)
p[i]=min(p[2*id-i],mx-i);

2*id-i是i关于id的对称点(上图j)(证明:i-id=id-j),而p[j]表示以j为中心的最长回文半径,这样我们就可以利用p[j]和mx加快速度了。

为什么要用p[j]和mx-i取min来更新,什么鬼?

淡定,淡定。我们想一下,p[j](以j为中心的最长回文半径)是已经知道了(因为是从前面扫过来的),若是p[j]>mx-i,我们是可以知道以j为中心,以mx的对称点到j的距离为半径形成的回文字符串是肯定存在的,并且id的左边直到mx的对称点与id的右边 直到mx是一一对应的,不难理解mx是i目前可以更新到的最大回文半径;若p[j]<mx-i,证明j的回文半径不到mx的对称点到j的距离,再次通过(id的左边直到mx的对称点与id的右边 直到mx是一一对应的),不难想到p[i]=p[j]。

取完min就是最大的回文半径吗?

显然不是,接下来的暴力往后扫就好了(学oi的都有暴力倾向)。

三、代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; char s[11000002];
char s_new[21000002];//存添加字符后的字符串
int p[21000002]; int Init() {//形成新的字符串
int len=strlen(s);//len是输入字符串的长度
s_new[0]='$';//处理边界,防止越界
s_new[1]='#';
int j=2;
for(int i=0;i<len;i++) {
s_new[j++]=s[i];
s_new[j++]='#';
}
s_new[j]='\0';//处理边界,防止越界(容易忘记)
return j;// 返回s_new的长度
} int Manacher() {//返回最长回文串
int len=Init();//取得新字符串的长度, 完成向s_new的转换
int max_len=-1;//最长回文长度
int id;
int mx=0;
for(int i=1;i<=len;i++) {
if(i<mx)
p[i]=min(p[2*id-i],mx-i);//上面图片就是这里的讲解
else p[i]=1;
while(s_new[i-p[i]]==s_new[i+p[i]])//不需边界判断,因为左有'$',右有'\0'标记;
p[i]++;//mx对此回文中点的贡献已经结束,现在是正常寻找扩大半径
if(mx<i+p[i]) {//每走移动一个回文中点,都要和mx比较,使mx是最大,提高p[i]=min(p[2*id-i],mx-i)效率
id=i;//更新id
mx=i+p[i];//更新mx
}
max_len=max(max_len,p[i]-1);
}
return max_len;
} int main()
{
scanf("%s",&s);
printf("%d",Manacher());
return 0;
}

四、复杂度

完结撒花(复杂度不会证明呀,因为我是蒟蒻)

Manacher(马拉车)————O(n)回文子串的更多相关文章

  1. Manacher算法——最长回文子串

    一.相关介绍 最长回文子串 s="abcd", 最长回文长度为 1,即a或b或c或d s="ababa", 最长回文长度为 5,即ababa s="a ...

  2. Manacher算法----最长回文子串

    题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些 ...

  3. 马拉车算法——求回文子串个数zoj4110

    zoj的测评姬好能卡时间.. 求回文子串的个数:只要把p[i]/2就行了: 如果s_new[i]是‘#’,算的是没有中心的偶回文串 反之是奇回文串 /* 给定两个字符串s,t 结论:s,t不相同的第一 ...

  4. Manacher 求最长回文子串算法

    Manacher算法,是由一个叫Manacher的人在1975年发明的,可以在$O(n)$的时间复杂度里求出一个字符串中的最长回文子串. 例如这两个回文串“level”.“noon”,Manacher ...

  5. manacher求最长回文子串算法

    原文:http://www.felix021.com/blog/read.php?2040 首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个 ...

  6. hdu 3068 最长回文(manacher&amp;最长回文子串)

    最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  7. manacher hihoCoder1032 最长回文子串

    居然能够做到O(n)的复杂度求最长回文.,也是给跪了. 以下这个人把manacher讲的很好,,能够看看 http://blog.csdn.net/xingyeyongheng/article/det ...

  8. hdu 3068 最长回文 【Manacher求最长回文子串,模板题】

    欢迎关注__Xiong的博客: http://blog.csdn.net/acmore_xiong?viewmode=list 最长回文                                 ...

  9. manacher求最长回文子串算法模板

    #include <iostream> #include <cstring> #include <cstdlib> #include <stdio.h> ...

  10. 【LeetCode】5. Longest Palindromic Substring 最大回文子串

    题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...

随机推荐

  1. 电脑进入bios和u盘启动快捷键

    参考:http://www.jb51.net/os/78638.html 一:联想系列 1:联想笔记本电脑 Thinkpad idea 520  :关机状态下,在左下角用回形针捅小孔,知道出现bios ...

  2. java面试一日一题:如何设计一款垃圾回收器

    问题:如果让你设计一个垃圾回收器,你会考虑哪些问题 分析:该问题主要考察对java中垃圾回收器的理解,要理解怎么回收:一款好的垃圾回收器有哪些衡量指标 回答要点: 主要从以下几点去考虑, 1.垃圾回收 ...

  3. Rabbit MQ一些参数解释

    //ConnectionFactory(连接工厂): 生产Connection的的工厂 //Connection(连接):是RabbitMQ的socket的长链接,它封装了socket协议相关部分逻辑 ...

  4. Pytorch系列:(六)自然语言处理NLP

    这篇文章主要介绍Pytorch中常用的几个循环神经网络模型,包括RNN,LSTM,GRU,以及其他相关知识点. nn.Embedding 在使用各种NLP模型之前,需要将单词进行向量化,其中,pyto ...

  5. Linux_配置主DNS服务(基础)

    [RHEL8]-DNSserver:[Centos7.4]-DNSclient !!!测试环境我们首关闭防火墙和selinux(DNSserver和DNSclient都需要) [root@localh ...

  6. python 从2个文件中提取不相同的内容并输出到第三个文件中

    #-*- coding: UTF-8 -*- import re import sys import os   str1=[] str2=[] str_dump=[] fa=open("A. ...

  7. Jquery的load加载本地文件出现跨域错误的解决方案"Access to XMLHttpRequest at 'file:///android_asset/web/graph.json' from(Day_46)

    博主是通过JS调用本地的一个json文件赋值给变量出现的跨域错误, 网上有大量文章,五花八门的,但总归,一般性此问题基本可通过这三种方法解决: https://blog.csdn.net/qq_418 ...

  8. Java安全之Cas反序列化漏洞分析

    Java安全之Cas反序列化漏洞分析 0x00 前言 某次项目中遇到Cas,以前没接触过,借此机会学习一波. 0x01 Cas 简介 CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用 ...

  9. 关于unity贴图压缩

    unity官方 https://docs.unity3d.com/Manual/class-TextureImporterOverride.html //后续填充内容

  10. unity 2017 卡在 loading界面

    看了网上很多方法,都不奏效. 提供一个简单的方法,不妨一试! 打开其他版本unity,登陆你的账户,再打开unity2017即可!