【leetcode 5】最长回文子串, Manachers算法

  • 解法一
    枚举每个回文的中心(回文中心可能是一个字符,也可能是两个字符,例子分别是:cac,caac),从这个回文中心出发向两边扩散,直到扩到不能再扩,记录下该回文中心能够产生的最长回文字符串的起始、终止位置;
    与全局最长回文字符串的起始、终止位置比较,记录下最长回文字符串。
class Solution:
    def expand(self,s,l,r):
        while l>=0 and r<len(s) and s[r]==s[l]:
            l-=1
            r+=1
        return l+1,r-1

    def longestPalindrome(self, s: str) -> str:
        start,end=0,0
        for i in range(len(s)):
            left1,right1=self.expand(s,i,i)
            left2,right2=self.expand(s,i,i+1)
            if right1-left1>end-start:
                start,end=left1,right1
            if right2-left2>end-start:
                start,end=left2,right2
        return s[start:end+1]
    

解法2: Manacher算法

在上面枚举每一个回文中心 向左右两边扩散的解法的基础上,考虑如何复用已经求出来的信息。
现在仅考虑长度为奇数的字符串,
假设以索引j为中心的最长回文字符串(回文字符串的一半的长度为arm_len[j])已经找到,问如何利用这一信息求之后的索引i作为回文中心时的长度?

对于之后的索引i,

  • 首先,求以s[i]为中心时最长回文子串的臂长,记为cur_arm_len
    这个过程分为两个步骤,
    首先,利用之前索引j的回文臂长信息arm_len[j]和目前最长回文子串能够到达的最远位置right,找到以s[i]为中心且不超过当前已知最长回文子串范围时的回文子串的臂长min_arm_len;(注:如果目前已知的以s[j]为中心的回文子串并不能覆盖i,那么arm_len[j]信息没用,所以可以跳过求min_arm_len这一步骤)
    接着,在min_arm_len的基础上,利用方法self.expand,继续向左右探索以s[i]为中心时可能的回文片段,直到不对称为止,并返回回文臂长。
  • 接着,记录以s[i]为中心时最长回文子串的臂长到数组arm_len中;
  • 然后,更新最近一次的已知回文中心j和最近一次的回文子串的最大索引right;
  • 最后,更新全局变量start,end(最长回文子串的起始、末尾位置)。
class Solution:
    def expand(self,s,l,r):
        while l>=0 and r<len(s) and s[l]==s[r]:
            l-=1
            r+=1
        return (r-l-2)//2  

    def longestPalindrome(self, s: str) -> str:
        start,end=0,0
        s='#'+'#'.join(s)+'#'
        arm_len=[]
        right=-1
        j=-1
        for i in range(len(s)):
            if i<=right:
                i_sym=2*j-i
                min_arm_len=min(right-i,arm_len[i_sym])
                cur_arm_len=self.expand(s,i-min_arm_len,i+min_arm_len)
            else:
                cur_arm_len=self.expand(s,i,i)
            arm_len.append(cur_arm_len)
            if i+cur_arm_len>right:
                right=i+cur_arm_len
                j=i
            if 2*cur_arm_len+1>end-start:
                start,end=i-cur_arm_len,i+cur_arm_len
        return s[start+1:end+1:2]

相关推荐

  1. leetcode 5, Manachers算法

    2024-04-09 13:22:03       39 阅读
  2. ManacherLeetCode-5.

    2024-04-09 13:22:03       56 阅读
  3. LeetCode-5

    2024-04-09 13:22:03       50 阅读
  4. LeetCode_5_中等_

    2024-04-09 13:22:03       56 阅读
  5. leetcode 5.

    2024-04-09 13:22:03       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-09 13:22:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-09 13:22:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-09 13:22:03       82 阅读
  4. Python语言-面向对象

    2024-04-09 13:22:03       91 阅读

热门阅读

  1. MSF-Linux系统攻防

    2024-04-09 13:22:03       33 阅读
  2. Arteris 的noc和arm 的nic-400 有什么区别?

    2024-04-09 13:22:03       32 阅读
  3. arm 的CoreLink 是什么?

    2024-04-09 13:22:03       33 阅读
  4. Linux C++ 024-STL初识

    2024-04-09 13:22:03       33 阅读
  5. 原生js封装请求组件

    2024-04-09 13:22:03       33 阅读
  6. ChatGPT革新学术论文写作:提升写作效率与质量

    2024-04-09 13:22:03       38 阅读
  7. 【算法】最长连续递增序列 - 贪心算法

    2024-04-09 13:22:03       30 阅读
  8. 渗透测试概述

    2024-04-09 13:22:03       37 阅读