首页 > 其他分享 >Manacher 学习笔记

Manacher 学习笔记

时间:2024-10-14 23:32:52浏览次数:7  
标签:Manacher 笔记 学习 字符串 改造 半径 我们 回文

Manacher,又名马拉车算法,是一种能在 \(O(n)\) 的时间复杂度之内求出一个字符串的最长回文字串的巧妙算法,其与 exKMP 有一点相似之处

Part1:实现步骤

step1:改造字符串

首先,我们要对字符串进行改造
因为在原字符串中会有 奇回文串和偶回文串,要分两种情况,不好处理,所以我们要改造字符串,使其只有一种情况

那么我们怎么改造呢?
很简单:
只用在原串的开头结尾以及每个字符之间加上一个未在字符集中出现过的特殊字符即可
并且,我们规定改造出来的字符串下标从一开始,下标为 \(0\) 的地方放另外一个特殊字符来防止越界

改造示意如下:
image

改造好了之后我们会发现,所有回文串都是奇回文串了,有一个回文中心。

step2:回文半径

以 \(i\) 为中心的回文串的长度的一半,叫做回文半径(注意,这里的长度的一半要向上取整)
举个栗子
image
其中的 \(d[]\) 数组就是指的以 \(i\) 为中心的回文半径

step3:加速!

假设我们现在已经找到了一个在当前最靠右的回文串 \(T\)
image

就是图中的绿色部分,然后我们已经推完了其回文中心 \(6\) 以前的 回文半径,接下来我们要继续向后推点 \(7\) ,那该怎么办?

我们完全可以利用上回文的性质:
既然点 \(7\) 处在这个回文串中,那么它必然与关于回文中心对称的 \(5\) 相等.那么我们就可以利用上 \(5\) 的信息——— \(7\) 的左右两个也必然相等
这就是第一种情况:当 \(i\) 处在 \(T\) 之中时,便可利用上与之关于回文中心对称的点 \(i'\) 的信息。
当然,这种情况也分两种小情况:

  • 当 \(i\) 加上 \(i'\) 的回文半径之后仍然在 \(T\) 之中,\(d[i]=d[i']\)
  • 当 \(i\) 加上 \(i'\) 的回文半径之后不在 \(T\) 之中 那么在 先将 \(d[i]\) 赋值为 在 \(T\) 之内的长度,在 \(T\) 之外的部分直接 暴力 去求

在上面的那幅图中的 \(d[9]\) 又是为什么只有 \(1\) 呢?
因为 \(9\) 在字符串边缘啊,向右只有这么多字符了

那自然,还有 \(i\) 不处在 \(T\) 之中的情况,这种直接暴力解决

在处理完上面的情况之后,我们还要更新一下 \(T\)
如果 \(i+d[i]-1>r_t\) ,那么最靠右的回文串就是 以 \(i\) 为回文中心的回文串

最后得出结果:原串的最长回文串=新串的最大回文半径-1

Part3:时间复杂度分析

很显然的,\(i\) 从左到右扫一遍 \(O(n)\)

然后暴力的部分最多扫 \(n\) 个,因为 每次暴力都会将 最靠右的回文串向右挪,所以最多 \(O(n)\)

总复杂度 \(O(n)\)

结束!
上代码!

#include<bits/stdc++.h>
using namespace std;
string chuan;
string new_;
int d[23451400];
int main()
{
    ios::sync_with_stdio(0);
    cin>>chuan;
    new_.push_back('%');//插入开头特殊字符 
    for(int ww=1;ww<=chuan.size();ww++)//改造回文串 
    {
        new_.push_back('#');
        new_.push_back(chuan[ww-1]);
    }
    new_.push_back('#');
    //get_d;
    d[1]=1;//d[1]=1 
    int max_=1;//最大的d值 
    for(int i=2,l=0,r=1;i<new_.size();i++)//l和r就是当前最靠右的回文串的左右端点 
    {
        if(i<=r)//如果当前的 i 在这个回文串中 
        {
            d[i]=min(d[r-i+l],r-i+1);//直接传递没有问题的部分 
        }
        while(new_[i-d[i]]==new_[i+d[i]])//剩下的部分暴力枚举 
        {
            d[i]++;
        }
        if(i+d[i]-1>r)//更新回文串位置 
        {
            l=i-d[i]+1;
            r=i+d[i]-1;
        }
        max_=max(max_,d[i]);
    }
    cout<<max_-1;
    return 0;
}

标签:Manacher,笔记,学习,字符串,改造,半径,我们,回文
From: https://www.cnblogs.com/sea-and-sky/p/18466268

相关文章

  • 基于人工智能的图像分类算法研究与实现 - 深度学习卷积神经网络图像分类
    毕业设计-基于人工智能的图像分类算法研究与实现-深度学习卷积神经网络图像分类文章目录0简介深度学习作为机器学习领域内新兴并且蓬勃发展的一门学科,它不仅改变着传统的机器学习方法,也影响着我们对人类感知的理解,已经在图像识别和语音识别等领域取得广泛的应用......
  • C++模板初阶,只需稍微学习;直接起飞;泛型编程
    ......
  • 计算机二级备考笔记(第四期)
    易错知识点:1.直接反映计算机计算能力与精度的指标参数是字长;2.循环链表、双向链表可以不重复访问到所有结点;3.企业之间的商务(Business-to-Business,B2B);代理商、商家和消费者三者之间的电子商务(Agents-to-Business-to-Consumer,ABC);消费者与消费者间的电子商务(Consumer-to-Consu......
  • C语言学习笔记(3)
    提前批第二题:#include<stdio.h>#defineN10voidReadData(inta[],intn);voidPrintData(inta[],intn);voidMaxMinExchange(inta[],intn);voidmain(){ inta[N],n; printf("Inputn(n<=10):\n"); scanf("%d",&n); if(n>0&......
  • Latex学习笔记
    博客【LaTeX】新手教程:从入门到日常使用@DylaaanTeXworks使用指南LaTeX新手入门以及TeXlive和TeXstudio的安装使用快速上手系列——用Overleaf写中文文档常用数学符号的LaTeX表示方法——较为简略Latex公式手册——号称全网最全......
  • 【油猴脚本】00027 案例 Tampermonkey油猴脚本, 仅用于学习,不要乱搞。添加标题为网页数
    前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦......
  • C语言学习第二章
    目录1、程序设计1.1、选择结构1.2、循环语句1.3、break(退出)与continue(继续)1.4、goto语句2、例题1、求解1~100的和2、从键盘上输入一个学生的成绩,判断该学生成绩等级:3、完成两个数的四则运算4、输入整数a和整数b,将a时将其反序<>5、从键盘输入一个三位整数,判断它......
  • DBPM: 增强时间序列对比学习:一种动态坏对挖掘方法《Towards Enhancing Time Series Co
    今天是2024年10月12日,思路枯竭,还是论文看的太少了,继续看论文.论文:TowardsEnhancingTimeSeriesContrastiveLearning:ADynamicBadPairMiningApproach或者是:TowardsEnhancingTimeSeriesContrastiveLearning:ADynamicBadPairMiningApproachGitHub:https://git......
  • 机器学习和神经网络的研究与传统物理学的关系
    将2024年诺贝尔物理学奖授予机器学习与神经网络领域的研究者,这一决定无疑具有里程碑式的意义,它不仅标志着物理学界对交叉学科研究的认可,也体现了科学技术发展趋势的深刻变革。以下是我对这一评奖结果的几点看法:科学边界的拓展:传统上,诺贝尔物理学奖聚焦于对自然界基本规律的理......
  • Manacher 算法
    \(Manacher\)算法\(Manacher(马拉车)\)算法,是一种高效解决最长回文子串问题的算法。其\(O(n)\)的复杂度相较于暴力\(O(n^2)\)和字符串哈希\(O(nlogn)\)来说,快了不少。算法实现:首先说一下暴力的解法,对于每一个字符串上的字符,考虑以其为起点,向两边扩展。若字符串上回文......