manacher算法详解(马拉车算法)

马拉车算法

Manacher算法是由题目“求字符串中最长回文子串的长度”而来。比如 abcdcb 的最长回文子串为 bcdcb ,其长度为5。

回文:正着念,反着念都一样
在这里插入图片描述
暴力解不容易,要分情况 解决长度为奇数和长度为偶数 回文的问题
具体做法:以每个位置为中心,向两边扩。(只适合于 长度为奇数的情况)
在这里插入图片描述
但是偶回文就扩不了了!
下图,无论是从哪一个数字开始扩,回文长度 都只能是1
在这里插入图片描述
这种情况下,我们只能向 字符串中各个字符之间 加东西!
比如这种情况,既有奇回文,又有偶回文
在这里插入图片描述
具体怎么插入呢?如下图:
数字的含义 是该位置的回文长度
在这里插入图片描述
在这里插入图片描述
最长回文就是最大值除以2,11/2=5
在这里插入图片描述
在这种情况下,无论是奇回文,还是偶回文,我们都可以找到!

注意:加的字符串。不仅仅只能为#,加什么都行,不影响结论。

时间复杂度估计:O(N²) (因为实质上是一个等差数列1+2+ … )

而manacher算法 时间复杂度估计:O(N)
为进一步详细介绍,我们先简单介绍几个概念:

1.回文直径与回文半径:
在这里插入图片描述
2.回文半径数组 pArr : parr【位置】=回文半径
在这里插入图片描述
3.最右回文右边界 R : 来到的最右位置的字符 !
在这里插入图片描述
最右回文右边界对应的回文中心 C :
在这里插入图片描述
总结:

处理回文子串长度为偶数的问题:上面拿 abcdcb 来举例,其中 bcdcb 属于一个回文子串, 但如果回文子串长度为偶数呢?像
cabbac ,按照上面定义的“扩”的逻辑岂不是每个字符的回文半径都是0, 但事实上 cabbac 的最长回文子串的长度是6。
因为我们上面“扩”的逻辑默认是将回文子串当做奇数长度的串来看的, 因此我们在使用Manacher算法之前还需要将字符串处理一下, 这里有一个小技巧,那就是将字符串的首尾和每个字符之间加上一个特殊符号,这样就能将输入的串统一转为奇数长度的串了。比如 abba 处理过后为
#a#b#b#a ,这样的话就有charArr[4]=’#’ 的回文半径为4,也即原串的最大回文子串长度为4。

接下来分析,manacher算法是如何利用遍历过程中计算的 pArr 、 R 、 C 来为后续字符的回文半径的求解加速的
**情况1是,**遍历到的字符下标i 在 R 的右边(起初另 R=-1 ),这种情况下该字符的最大回文半径pArr[i] 的求解无法加速,只能一步步向外扩来求解。(暴力扩)
例子:
从0位置扩的时候,最右回文右边界 R在-1位置,( 即 i位置不再回文右边界里面,这个时候暴力扩就 完事了!
在这里插入图片描述
0位置扩的时候,回文右边界 来到 0位置
在这里插入图片描述
所以,到了1的时候,回文右边界还是在1的左面,所以还是暴力扩
在这里插入图片描述
此时,回文右边界来到这儿 2的位置
在这里插入图片描述
当来到2的时候,发现在回文右边界里面了,这时介绍情况2。
在这里插入图片描述
情况2是,遍历到的字符下标 i 在回文右边界 R 内,这时 pArr[i] 的求解过程可以利用之前遍历的字符回文半径信息来加速。

分别做 cur 、 R 关于 C 的对称点L :
在这里插入图片描述
i一定在c的右面
在这里插入图片描述
根据c做 i 的对称点在这里插入图片描述
我们有 每个位置回文半径的长度,且都纪录在 一个数组中(回文半径数组),

这个数组可以告诉我,求 i‘ 的回文区域是哪一段

例子:

在这里插入图片描述
i 和 i‘ 的回文半径在 L R之间
在这里插入图片描述
在这里插入图片描述
此时,i 位置的回文半径直接知道答案。
即,和 i‘ 一样

先证明 这一部分是回文:
在这里插入图片描述
如下图。1是回文,c整体是回文,2和c对称,所以,是一个镜像的关系,所以2是1的 逆序,所以2是回文
在这里插入图片描述
接下来证明 后面的不是回文。
逻辑顺序按1 2 3
在这里插入图片描述
可能性3:i‘ 自己的回文范围,L和R没报包住在这里插入图片描述
例子:
在这里插入图片描述
在这里插入图片描述
长度直接为 i 到R
在这里插入图片描述
证明:
在这里插入图片描述
因为大回文,所以 x≠x‘
在这里插入图片描述
所以,x ≠ y

综上所述,共四种可能性:

  1. i 在 R 外
  2. i 在 R 内(分为3种情况)
    2.1 i‘ 的回文半径在 L和R里面 O(1)
    2.2 i‘ 的回文半径在 L和R外面 O(1)
    2.3 i‘ 的回文半径在 跟L压线

下面讲2.3
例子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
每个字符都尝试向外扩到最大并更新 R (只增不减),每次 R 增加的量就是此次能扩的字符个数,而 R 到达串尾时问题的解就能确定了,因此时间复杂度就是每次扩操作检查的次数总和,也就是 R 的变化范围( -1~2N ,因为处理串时向串中添加了 N+1 个 # 字符),即O(1+2N)=O(N) 。

第一种可能性:
在这里插入图片描述
在这里插入图片描述
第二种可能性:
在这里插入图片描述
第三种可能性:
在这里插入图片描述
应用:
给你一个字符串,要求添加尽可能少的字符使其成为一个回文字符串。
思路:当 R 第一次到达串尾时,做 R 关于 C 的对称点 L ,将 L 之前的字符串逆序就是结果
在这里插入图片描述
前面不是回文的部分,逆序过来,就是答案。
在这里插入图片描述
如何做:
改写manacher算法

当发现回文右边界扫到了字符串最后一个位置,

这时候,得到了 c和回文 右边界 R,
也能得到L,
这时,L前面的,不是回文的部分逆序,直接出答案
在这里插入图片描述
偶回文情况:
在这里插入图片描述
在这里插入图片描述

进阶1 01.51.18 开始扩

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值