《manacher》基础概念

一、算法概述

  1. 定义:Manacher算法用于在给定字符串中高效地找出最长回文子串,通过对字符串进行预处理和利用回文子串的对称性,将时间复杂度优化至线性。
  2. 核心思想
    • 对原字符串插入特殊字符,将奇数长度和偶数长度的回文统一为奇数长度回文。
    • 利用已计算的回文半径,通过对称性减少重复计算,快速扩展新位置的回文半径。
  3. 应用场景
    • 字符串处理中查找最长回文子串(如文本编辑器的回文检测)。
    • 密码学中的模式匹配(检测回文结构的密码特征)。

二、算法思路

  1. 字符串预处理
    • 在原字符串的每个字符之间插入一个特殊字符(如$),并在首尾添加不同的特殊字符(如#),使所有回文子串长度变为奇数。例如,字符串"aba"变为"#a b b ba#"。
  2. 回文半径数组
    • 定义数组p[i]表示以字符str[i]为中心的最长回文子串的半径(包含自身)。例如,"#a b b ba#“中p[3] = 4(以b为中心的回文子串为"a b b ba”,半径为4)。
  3. 利用对称性加速
    • 若已知str[ct]为中心的回文子串覆盖str[i](即i < r,其中r为当前最右回文边界),则str[i]的回文半径p[i]可利用str[2*ct-i]的对称性快速初始化。
  4. 回文半径扩展
    • 从初始化的p[i]开始,向两侧扩展,直到字符不匹配或超出边界,更新p[i]的最大值。
  5. 边界更新
    • 每次扩展后,若str[i]的回文边界超过当前最右边界r,则更新中心位置ct和边界r

三、伪代码实现

1. 数据结构与全局变量

常量 maxn = 1000010  # 最大字符串长度
常量 split = '$'  # 插入的特殊字符
数组 p[maxn]  # 记录每个字符的回文半径
数组 strTmp[maxn]  # 临时存储原字符串

2. 核心函数框架

算法:Manacher算法
输入:字符串 str
输出:最长回文子串的长度

函数 ManacherPre(str):
    # 字符串预处理:插入特殊字符
    将 str 复制到 strTmp
    i = 0
    while strTmp[i] 不为空字符:
        str[2*i] = split
        str[2*i+1] = strTmp[i]
        i = i + 1
    str[2*i] = split
    str[2*i+1] = 空字符

函数 ManacherMatch(a, b):
    # 判断两个字符是否相等
    return a == b

函数 Manacher(str):
    ManacherPre(str)  # 预处理字符串
    ct = 0  # 当前最右回文区域的中心位置
    r = 0  # 当前最右回文区域的右边界
    maxLen = 1  # 最长回文子串的长度
    p[0] = 1  # 初始化第一个字符的回文半径

    for i from 1 to str的长度 - 1:
        # 1. 计算 p[i] 的初始值
        if i < r:
            p[i] = min(p[2*ct-i], r-i)
        else:
            p[i] = 0

        # 2. 扩张 p[i],让 p[i] 达到最大值
        while i - p[i] >= 0 且 ManacherMatch(str[i-p[i]], str[i+p[i]]):
            p[i] = p[i] + 1

        # 3. 更新 ct 和 r
        if i + p[i] > r:
            ct = i
            r = i + p[i]

        # 4. 更新最长回文
        if 2*p[i] - 1 > maxLen:
            maxLen = 2*p[i] - 1

    return maxLen

# 主程序(示例)
输入字符串 str
输出 Manacher(str)

四、算法解释

1. 预处理过程

  • 通过插入特殊字符,将所有回文子串统一为奇数长度,简化后续计算。例如,“abba"变为”#a b b bb$a#",每个回文子串中心明确。

2. 回文半径初始化

  • 对称性利用:若i在当前最右回文区域内(i < r),则p[i]可初始化为p[2*ct-i]r-i的较小值。
    • 原理:由于回文的对称性,str[i]str[2*ct-i]的回文半径在一定范围内相同,r-i确保不超出当前已知回文边界。
  • 边界外情况:若i >= r,则p[i]初始化为0,需从头开始扩展。

3. 回文半径扩展

  • 从初始化的p[i]开始,通过比较str[i-p[i]]str[i+p[i]],不断扩大回文半径,直到字符不匹配或超出边界。

4. 边界更新与结果记录

  • 每次扩展后,若i + p[i]超过当前最右边界r,则更新ct = ir = i + p[i],为后续计算提供新的对称参考。
  • 记录2*p[i] - 1的最大值(减去1是因为半径包含中心字符),即为最长回文子串的长度。

5. 示例演示

  • 原字符串:“abba”
  • 预处理后:“#a b b bb$a#”
  • 计算过程:
    • i=0p[0]=1,更新ct=0, r=1
    • i=1p[1]=2(对称于p[0]),更新ct=1, r=3
    • i=2p[2]=1,不更新边界。
    • i=3p[3]=4(扩展得到最长回文"a b b ba"),更新ct=3, r=7
    • 最终最长回文长度为2*4 - 1 = 7(对应原字符串"abba")。

五、复杂度分析

  1. 时间复杂度
    • 预处理:O(n),插入特殊字符遍历一次字符串。
    • 回文半径计算:每个字符最多被访问一次(扩展过程中每个字符仅需比较一次),总时间复杂度为O(n)。
    • 整体时间复杂度:O(n)。
  2. 空间复杂度
    • 存储回文半径数组p和临时字符串strTmp,空间复杂度为O(n)。
  3. 优势与局限
    • 优势:线性时间解决最长回文子串问题,比暴力枚举(O(n²))高效。
    • 局限:需额外空间存储预处理字符串和回文半径数组,不适用于空间受限场景。

  本文为作者(英雄哪里出来)在抖音的独家课程《英雄C++入门到精通》、《英雄C语言入门到精通》、《英雄Python入门到精通》三个课程的配套文字讲解,如需了解算法视频课程,请移步 作者本人 的抖音直播间。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值