最长回文子串之Manacher算法

Manacher算法

之前的动态规划和中心扩展算法都要考虑到字符串长度的奇偶问题,要分两种情况处理;而且对于很多子串进行了重复访问。

1.解决奇偶问题

在字符前后加上#符号,使得字符串的长度为2×n+1,恒为奇数。

aba  ———>  #a#b#a#
abba ———>  #a#b#b#a#

在代码中为了解决边界问题,之后又在字符串前后分别加了‘$’和‘@’。

2.解决重复访问

我们把一个回文串中最左或最右位置的字符与其对称轴的距离称为回文半径。Manacher定义了一个回文半径数组RL,用RL[i]表示以第i个字符为对称轴的回文串的回文半径。我们一般对字符串从左往右处理,因此这里定义RL[i]为第i个字符为对称轴的回文串的最右一个字符与字符i的距离。对于上面插入分隔符之后的两个串,可以得到RL数组:

char:    # a # b # a #
 RL :    1 2 1 4 1 2 1
RL-1:    0 1 0 3 0 1 0
  i :    0 1 2 3 4 5 6

char:    # a # b # b # a #
 RL :    1 2 1 2 5 2 1 2 1
RL-1:    0 1 0 1 4 1 0 1 0
  i :    0 1 2 3 4 5 6 7 8

观察可得,解决问题的关键就是求RL-1这个数组。
在这里插入图片描述

Code:

要注意输入字符串为空时,返回的为第一个字符‘$’;列表lens表示RL-1。

class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        if len(s)<=1:
            return s
        new = '$#' + '#'.join(s) + '#@'
        center, right, lens = 0, 0, [0] * len(new)
        for i in range(1, len(new)-1):
            if i < right:
                lens[i] = min(lens[2*center-i], right-i)
            while new[i-lens[i]-1] == new[i+lens[i]+1]:
                lens[i] += 1
            if lens[i] + i > right:
                right = lens[i] + i
                center = i
        maxlen = max(lens)
        index = lens.index(maxlen)
        res = new[index-maxlen:index+maxlen+1].replace('#', '')
        return res

Reference:

https://segmentfault.com/a/1190000003914228#articleHeader5
https://zh.wikipedia.org/wiki/最长回文子串

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值