LeetCode-5 最长回文子串

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/longest-palindromic-substring

题目描述

给你一个字符串 s,找到 s 中最长的回文子串。

 

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。


示例 2:

输入:s = "cbbd"
输出:"bb"


示例 3:

输入:s = "a"
输出:"a"


示例 4:

输入:s = "ac"
输出:"a"
 

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

解题思路

解法1:

这道题第一眼看上去就需要用动态规划的算法,然鹅众所周知动态规划一直是楼主的弱项。。所以我使用了中心扩展算法。

对于第i个字母来说,如果他是回文子串的中心,那么他只能有两种状态:1、他是回文子串的中心 2、他与i+1个字母共同组成了回文子串的中心,并且值与i+1个字母相同。假设他们均满足这两种情况,以他们为中心向两边进行扩展,计算出状态1和状态2的长度,找出最长。用这个思路将字符串遍历一遍,然后返回最大值,这个题就解完了,但是就如结果所示那样,这个解法的时间复杂度是O(n2),时间较长,倒是另一种manacher算法很有趣,时间复杂度也更低。

解法2:

在解法1的中,每换一次中心就需要重新求一次回文子串,那么之前计算过的回文子串是不是可以简单的利用一下帮助之后的回文子串的生成?答案是肯定的。

首先为了将双中心子串,如abba的子串也变成单中心的子串,我们在每个字母中间加入了‘#’,这样abba子串会变成a#b#b#a单中心子串,而单中心子串aba变成了a#b#a也还是单中心子串。

先引入一个臂长的概念,如果以i为中心,回文长度为i + 2 * r的回文子串,那么,r就为i位置的臂长。

 

 所以可以省去很多的比较。最终复杂度达到O(n)。

 

解法1:

复制代码
class Solution:
    def longestPalindrome(self, s: str) -> str:
        # 中心扩展算法
        if len(s) < 1: return ""
        L = 0
        R = 0
        i=0
        while i<len(s):
            len1 = Solution.kuozhan(self, i,i, s)
            len2 = Solution.kuozhan(self, i, i + 1, s)
            lenx = max(len1, len2)
            if lenx > R - L:
                L = i - (lenx - 1) // 2
                R = i + lenx // 2
            i+=1
        return s[L:R + 1]

    def kuozhan(self, start: int, end: int, s: str) -> int:
        L = start
        R = end
        while L >= 0 and R < len(s) and s[L] == s[R]:
            L -= 1
            R += 1
        return R - L - 1
复制代码

解法2:

复制代码
class Solution:
    def longestPalindrome(self, s: str) -> str:
       #Manacher 算法
        news="#"
        for c in s:
            news+=c
            news+='#'
        lenr=[]
        R=-1
        C=0
        p2=0
        p1=0
        cL=0
        pL=0
        maxx=0
        maxc=0
        while p1<len(news):
            if p1>R:
                r=Solution.kuozhan(self,p1,1,news)
                lenr.append(r)
                R=p1+r-1
                C=p1
            else:
                p2=2*C-p1
                pL=p2-lenr[p2]+1
                cL=C-lenr[C]+1
                if cL<pL:
                    lenr.append(lenr[p2])
                elif cL>pL:
                    lenr.append(R-p1+1)
                else:
                    r=Solution.kuozhan(self,p1,R-p1+1,news)
                    lenr.append(r)
                    R=p1+r-1
                    C=p1
            if lenr[-1]>maxx:
                maxx=lenr[-1]
                maxc=p1
            p1+=1
        return  news[maxc-maxx+1:maxc+maxx].replace('#','')
    def kuozhan(self,z:int,r:int,s: str) -> int:
        L = z-r
        R = z+r
        while L >= 0 and R < len(s) and s[L] == s[R]:
            L -= 1
            R += 1
        return R - z
复制代码

 

运行结果

 

posted @   过客匆匆,沉沉浮浮  阅读(25)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示