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

  • 解法一
    枚举每个回文的中心(回文中心可能是一个字符,也可能是两个字符,例子分别是:cac,caac),从这个回文中心出发向两边扩散,直到扩到不能再扩,记录下该回文中心能够产生的最长回文字符串的起始、终止位置;
    与全局最长回文字符串的起始、终止位置比较,记录下最长回文字符串。
python 复制代码
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(最长回文子串的起始、末尾位置)。
python 复制代码
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]
相关推荐
JUNAI_Strive_ving5 分钟前
力扣6~10题
算法·leetcode·职场和发展
洛临_25 分钟前
【C语言】基础篇续
c语言·算法
戊子仲秋25 分钟前
【LeetCode】每日一题 2024_10_7 最低加油次数(堆、贪心)
算法·leetcode·职场和发展
__AtYou__1 小时前
Golang | Leetcode Golang题解之第455题分发饼干
leetcode·golang·题解
__AtYou__1 小时前
Golang | Leetcode Golang题解之第458题可怜的小猪
leetcode·golang·题解
osir.2 小时前
Tarjan
算法·图论·tarjan
绎岚科技2 小时前
深度学习中的结构化概率模型 - 从图模型中采样篇
人工智能·深度学习·算法·机器学习
福大大架构师每日一题2 小时前
文心一言 VS 讯飞星火 VS chatgpt (364)-- 算法导论24.3 6题
算法·文心一言
7yewh2 小时前
C语言刷题 LeetCode 30天挑战 (八)快慢指针法
linux·c语言·开发语言·数据结构·算法·leetcode·链表
武昌库里写JAVA3 小时前
Vue3常用API总结
数据结构·spring boot·算法·bootstrap·课程设计