【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_lenj)已经找到,问如何利用这一信息求之后的索引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]
相关推荐
hqyjzsb1 小时前
法律 Prompt 干货:搭建合同审查提示词要包含哪些要素
开发语言·人工智能·python·职场和发展·数据分析·prompt·业界资讯
Discipline10292 小时前
尼泊尔河流流量:天气驱动的预测与高流量风险
人工智能·算法
XuCoder2 小时前
改一个数,右边全得重算,这题怎么扛住两万次查询
算法
小羊没烦恼!2 小时前
在Scrum中实施敏捷建模
java·开发语言·windows·算法·c#
weixin_307779132 小时前
基于睿擎工业开发平台的预训练视觉模型轻量化适配与低代码部署优化
开发语言·算法
hold?fish:palm3 小时前
45 二叉树的右视图
开发语言·c++·算法
粤鼎恒业3 小时前
惠州工厂电子料回收厂家推荐:从交接单反推筛选标准
大数据·数据库·算法·硬件架构·硬件工程·pcb工艺·材料工程
小爷毛毛(卓寿杰)4 小时前
【Agent 意图识别】输出协议、评估与置信度
人工智能·算法·大模型·prompt·大语言模型·agent
优质酸酸乳4 小时前
力扣100题之21合并两个有序链表
算法·leetcode·链表
旖旎夜光4 小时前
LeetCode 137 : 只出现一次的数字 II(位运算) —— 题解
c++·笔记·学习·算法·leetcode·力控