最长回文子串 马拉车算法

马拉车算法(最长回文子串)

以 babad 为例

**思路:**肯定是要遍历,记录以每个字符为中心的回文串长度。(时间复杂度O^2)但这样做有一个问题,无法解决偶数长度的字符串,如abba,就无法得到4

马拉车算法会将每个字符间插入#

babad–> #b#a#b#a#d#

计算最长回文子串过程如下:

i012345678910
#b#a#b#a#d#
leni12141212121
max r0226666881010
max i01133333333

leni以i为中心的回文子串半径长度
max r当前最长的回文串右边界下标
max i当前最长的回文串中心所在下标

i<maxr,其实也要暴力扩散,但是我们可以尽可能减少扩散的迭代数。我们取[maxr-i,leni[2maxi-i]]最小值作为扩散的起点。2maxi-i即为i关于maxi的对称点。
i>=maxr,暴力扩散

我们知道,最终得到的回文串肯定是以#开头,以#结束的回文串。这是因为只有当两边字符不相等时才会停止左右扩散,所以#是边界。也就是说子串中#的数量肯定是比剩下的字符多1的、
我们得到最大的leni(例子为4)时,此时回文串长度为2leni-1(例子为7),而其中有(2leni-1)/2+1个字符#(例子为4),所以剩下的字符即为我们要求的回文串长度(例子为3)

再以偶数长度字符串举例。baab

i012345678
#b#a#a#b#
leni12125*2121
max r022488888
max i011355555

最大leni为5,此时回文串长度为9,其中有5个#,所以结果为4
回文串起始位置maxi-leni+1,结束位置maxi+leni-1
‘’,join(‘#’.split(s[maxi-leni+1:maxi+leni]))

class Solution(object):
    # 暴力扩散 返回右边界
    def expand(self,s, left, right):
        while (left >= 0 and right < len(s) and s[left] == s[right]):
            left -= 1
            right += 1
        return int((right - left) / 2)
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        appends = '#' + '#'.join(list(s)) + '#'
        leni = list()  # 以i为中心的回文子串半径长度
        maxr = -1  # 当前最长的回文串右边界下标
        maxi = -1  # 当前最长的回文串中心所在下标
        maxlen = 0  # 记录最长回文串半径
        leni_tmp=-1

        for i in range(len(appends)):
            if i >= maxr:
                leni_tmp = self.expand(appends, i, i)
            else:
                min_tmp = min(maxr - i, leni[2 * maxi - i])
                leni_tmp = self.expand(appends, i - min_tmp, i + min_tmp)
            leni.append(leni_tmp) # 用于记录每一个回文子串长度
            if leni_tmp > maxlen:# 更新当前最长子串
                maxi = i
                maxlen = leni_tmp
                maxr = i + leni_tmp - 1
        return ''.join(appends[maxi - maxlen + 1:maxlen + maxi].split('#'))

理解这个算法最好的办法就是把别人的代码自己跑一边,debug看看每一步的目的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值