[算法入土之路]Manacher算法

用处:

        降低大多数回文问题的时间复杂度, 提高程序效率

经典习题:

        5. 最长回文子串 - 力扣(LeetCode) (leetcode-cn.com)

代码实现:

""" @File   : Manacher
    
    @Author : BabyMuu
    @Time   : 2021/12/19 18:36
"""

class Manacher:
    '''
    在基础的方法上优化
        几个属性  i: 寻找回文长度的当前位置
                 R: 前序获得到的回文串的右边界
                 L: R对应回文串的左边界
                 center :  R 和 L 的中心位置
                 i': i 相对 center 的镜像对应元素
        优化方法:
            当 i < R 的时候
                根据 相对center的镜像获取到对应的元素的最长回文半径 pl[i']: len
                如果 len > r - i: 即 i' 的回文串左边界超出了 L
                    则 i 的回文串长度 就等于 r - i
                如果 i' - len == L 则
                    需要继续向外匹配(R + 1 与 i - len -1 位置对比)
                        与暴力解相同
                如如果 i - len > l:
                    则  i 的回文长度 与 i' 相同
            如果 i >= R
                暴力解 无法加速
    '''

    def __init__(self, pri_str):
        self.manacher = f'#{"#".join(pri_str)}#'
        self.pal_arr = [0 for i in self.manacher]

    def maximum_palindrome_length(self):
        loc, len_ = self.algorithm()
        return self.manacher[loc - len_: loc + len_ + 1].replace('#', '')

    def algorithm(self):
        center = right = -1
        max_ = -1
        max_str = None
        for i in range(len(self.manacher)):
            # 获取最小查找长度
            self.pal_arr[i] = min(self.pal_arr[2 * center - i], right - i) if right > i else 1
            '''👆 i > 右侧边界位置 则 为 1
                else        # 2 * center - i ==>  找到     i 相对于 center 的镜像位置
                    1 i' - len == L 俩相同
                    2 len > r - i   --> right - i
                    3 i - len > l   --> self.pl_arr[2 * center - i]
            '''
            while i + self.pal_arr[i] < len(self.manacher) and i - self.pal_arr[i] > -1:
                if self.manacher[i + self.pal_arr[i]] == self.manacher[i - self.pal_arr[i]]:  # 向外辐射 看是否能找到更长的回文元素
                    self.pal_arr[i] += 1  # 如果有则加 1
                else:  # 一旦碰到不相同的元素 则说明没有使此回文串更长的回文元素了
                    break
            if i + self.pal_arr[i] > right:  # 如果右边界扩充了  则更新边界信息和中心信息
                right = i + self.pal_arr[i]
                center = i
            if max_ < self.pal_arr[i]:
                max_str = i  # 最长回文子串中心点
                max_ = self.pal_arr[i]  # 最长回文子串半径
        return max_str, max_ - 1  # 子串中心点位置, 抛去中心点的长度


测试及结果

if __name__ == '__main__':
    m = Manacher("papadada")
    print(m.manacher)
    print(m.algorithm())    # (11, 5)
    print(m.pal_arr)
    print(m.maximum_palindrome_length())    # adada
#  #  p  #  a  #  p  #  a  #  d  #  a  #  d  #  a  #
# [1, 2, 1, 4, 1, 4, 1, 2, 1, 4, 1, 6, 1, 4, 1, 2, 1]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值