leetcode5.最长回文子串

最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。


示例 1:

输入:s = "babad"

输出:"bab"

解释:"aba" 同样是符合题意的答案。


示例 2:

输入:s = "cbbd"

输出:"bb"

最优解决方案

有很多算法可以解决这个问题,但是其中最快的算法是Manacher(马拉车)算法,它的时间复杂度是 O(n),也就是说它只需要扫描一遍字符串就可以找到最长的回文子串。


具体来说,Manacher算法需要以下几个步骤:

  • 预处理字符串:在每个字符之间插入一个特殊字符(如 #),并在首尾加上不同的特殊字符(如 ^ 和 $),这样做的目的是消除奇偶性差异,使得所有回文子串都有奇数长度。
  • 初始化辅助数组 p:p[i] 表示以 i 为中心的最长回文半径,即 p[i]-1 就是以 i 为中心的最长回文子串长度。
  • 遍历预处理后的字符串:维护两个变量 center 和 right,分别表示当前已知回文子串能够达到右侧最远位置 right 的那个回文子串对应的中心位置 center 和右侧边界 right23。对于每个位置 i ,有以下三种情况:
  • 如果 i > right ,说明 i 不在当前已知回文子串能够覆盖到的范围内,那么就需要从头开始比较以 i 为中心向两边扩展是否相等,并更新 p[i], center 和 right 的值。
  • 如果 i <= right ,说明 i 在当前已知回文子串能够覆盖到的范围内,那么就可以利用对称性和已知信息来优化比较过程。具体地说,令 j = 2 * center - i 表示关于 center 对称于 i 的位置,则有以下两种情况:
  • 如果 p[j] < right - i ,说明以 j 为中心和以 i 为中心对应部分完全相同,并且不会超出右侧边界 right ,那么就可以直接令 p[i] = p[j]。
  • 如果 p[j] >= right - i ,说明以 j 为中心和以 i 为中心对应部分可能超出右侧边界 right 或者恰好达到右侧边界 right ,那么就需要从 right + 1 开始比较以 i 为中心向两边扩展是否相等,并更新 p[i], center 和 right 的值。
  • 找出最大值:遍历完预处理后的字符串后,在数组 p 中找出最大值 maxLen 和其对应下标 maxCenter ,则原始字符串 s 中最长回文子串长度为 maxLen-1 ,起始位置为 (maxCenter-maxLen)/2 (注意还原预处理后下标和长度)。

假设原始字符串 s = “babad” ,则预处理后的字符串为 “^#b#a#b#a#d#$” ,辅助数组 p 的初始值为 [0, 0, 0, 0, 0, 0, 0, 0, 0] 。下面是遍历过程中的情况:

  1. 当 i = 1 时,i > right ,所以从头开始比较以 i 为中心向两边扩展是否相等,发现没有相等的字符,所以 p[1] = 1 ,center 和 right 都不变。
  2. 当 i = 2 时,i > right ,所以从头开始比较以 i 为中心向两边扩展是否相等,发现有一个相等的字符 # ,所以 p[2] = 2 ,center = i , right = i + p[i] -1 =3。
  3. 当 i = 3 时,i <= right ,令 j = center *2 -i=1,则 p[j] < right -i=0 <1,所以直接令 p[3] = p[j]=1。
  4. 当 i =4时,i <=right ,令 j=center *2-i=2,则p[j]=right-i=2>=2,所以从right+1=4开始比较以i为中心向两边扩展是否相等,发现有两个相等的字符a和#,所以p[4]=4+2=6,center=i,right=i+p[i]-1=9。
  5. 当 i=5时,i<=right ,令j=center*2-i=3,则p[j]<right-i=4<5,所以直接令p[5]=p[j]=1。
  6. 当 i=6时,i<=right ,令j=center*2-i=4,则p[j]>=right-i=6>=3,所以从right+1=10开始比较以i为中心向两边扩展是否相等,发现没有相等的字符(超出字符串范围),所以p[6]=right-i+1=4。
  7. 当 i=7时,i<=right ,令j=center*2-i=5,则p[j]<right-i=2<4,所以直接令p[7]=p[j]=1。
  8. 当 i=8时,i>right ,所以从头开始比较以i为中心向两边扩展是否相等,发现没有相等的字符(超出字符串范围),所以p[8]=1。
  9. 遍历完预处理后的字符串后,在数组 p 中找出最大值 maxLen 和其对应下标 maxCenter ,则原始字符串 s 中最长回文子串长度为 maxLen-1 ,起始位置为 (maxCenter-maxLen)/2 (注意还原预处理后下标和长度)。在这个例子中, maxLen=p[4]=6,maxCenter=i,len=maxLen-1=(maxCenter-maxLen)/2=(4-6)/2=-1。因此原始字符串s中最长回文子串是"bab"。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值