5.最长回文子串

题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

【分析】本题有多种方法,例如中心扩散法,马拉车(Manacher)算法,动态规划法。

个人理解中心扩散法和马拉车算法都类似。其核心思想都是利用双指针从中间向两边开始判断是否符合回文串特征(左右对称)。

回文串有两种,一种是奇数长度的回文串,一种是偶数长度的回文串。奇数长度的是从中间某个元素开始向两边扩散(s[left]==s[right]),偶数长度的是从中间某两个元素开始向两边扩散。

所以在中心扩散法中分两种情况,一种是奇数回文串时,left=right开始迭代;另一种是偶数回文串时,right=left+1开始迭代。

而在马拉车算法中,把所有的字符串长度全部化为奇数的情况:添加分隔符。然后left=right同时向两边迭代,直到遇到边界条件为止。

class Solution:
    def longestPalindrome(self, s):      
        s='#'+'#'.join(s)+'#'   #添加分隔符
        size=len(s)
        if len(s)==2:
            return ""
        p=[]  #得到p数组
        for i in range(size):
            left=i
            right=i
            while left>=0 and right<size and s[left]==s[right]:
                left-=1
                right+=1    
            p.append(right-i)
        i=p.index(max(p))
        return ''.join(s[i-p[i]+1:i+p[i]-1].split("#"))

在这里插入图片描述
【动态规划法】首先定义状态,设 f ( i , j ) f(i,j) f(i,j)表示子串 s [ i , j ] s[i,j] s[i,j]是否是回文串,若是则为1,否则为0;

其次确定状态转移方程:
f ( i , j ) = { s [ i ] = = s [ j ] , j − i ≤ 1 s [ i ] = = s [ j ] a n d f ( i + 1 , j − 1 ) = = 1 , j − i &gt; 1 f(i,j)=\left\{\begin{matrix} s[i]==s[j],\quad \quad \quad \quad \quad \quad \quad \quad \quad \quad \quad \quad j-i\leq 1 \\ s[i]==s[j] \quad and \quad f(i+1,j-1)==1,j-i&gt;1 \end{matrix}\right. f(i,j)={s[i]==s[j],ji1s[i]==s[j]andf(i+1,j1)==1,ji>1

直观上,

  1. i i i为内循环, j j j为外循环; i ≤ j i \leq j ij,同时保证在得到 f ( i + 1 , j − 1 ) f(i+1,j-1) f(i+1,j1)的基础上再来得出 f ( i , j ) f(i,j) f(i,j)的结果(所以先循环 j : r a n g e ( l e n ( s ) ) j:range(len(s)) j:range(len(s)),再循环 i : r a n g e ( j + 1 ) ) i:range(j+1)) i:range(j+1))
  2. 因为$ f(i,j)==1 一 定 会 有 一定会有 f(i+1,j-1)==1 , 所 以 先 保 证 ,所以先保证 f(i+1,j-1)==1 , 然 后 判 断 子 串 的 首 尾 ,然后判断子串的首尾 s[i]==s[j]$ ,由此来得出$ f(i,j)$
class Solution:
    def longestPalindrome(self, s: str) -> str:
        size = len(s)
        if size<=1:
            return s
        dp=[[0]*size for _ in range(size)]
        len_max=1  #记录最大回文串的长度
        index=0 #记录最大回文串的首字符索引
        for j in range(size):
            for i in range(j+1):
                ## 状态转移:
                if j-i<=1 and s[i]==s[j]:
                    dp[i][j]=1
                elif j-i>1 and s[i]==s[j] and dp[i+1][j-1]==1:
                    dp[i][j]=1
                ##记录最大回文串信息:    
                if dp[i][j]==1:
                    if j-i+1>len_max:
                        len_max=j-i+1
                        index=i
        return s[index:len_max+index]

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值