LeetCode-5

5. 最长回文子串

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

Example
input
babad
output
aba
input
cbbd
output
bb
Note

思路

经典的动态规划问题

解法一:经典dp O(N2)O(N^2)O(N2)
dp[i][j]dp[i][j]dp[i][j]表示字符串[位置i......位置j][位置i......位置j][i......j]是否为回文串,根据回文串的性质
那么有:
                       {dp[i][j]=True(i==j)dp[i][j]=True(s[i]==s[j]并且i+1==j)dp[i][j]=dp[i+1][j−1](s[i]==s[j])\begin{cases}dp\left[ i\right] \left[ j\right]=True \left(i ==j\right)\\ dp\left[ i\right] \left[ j\right]=True \left( s\left[ i\right] ==s\left[ j\right] 并且 i+1==j\right)\\ dp\left[ i\right] \left[ j\right]=dp\left[ i+1\right] \left[ j-1\right] \left( s\left[ i\right] ==s\left[ j\right] \right)\end{cases}dp[i][j]=True(i==j)dp[i][j]=True(s[i]==s[j]i+1==j)dp[i][j]=dp[i+1][j1](s[i]==s[j])

关键在于状态转移,怎样确定每一个状态,使其没有后效性且对后面求解有利。
可以看到第三个式子中,我们可以先求去dp[i+1][j−1]dp[i+1][j-1]dp[i+1][j1]的布尔值,使后面的dp[i][j]dp[i][j]dp[i][j]快速判断,所以我们可以选择枚举iiijjj,那么可以对于一个jjj保持不变,枚举它的iii,那么第三个式子对应的是上个j−1j-1j1得到的dpdpdp值,完成动态规划

具体代码如下:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n < 2:        #小于2直接返回
            return s
        dp = [[False] * n for _ in range(n)]#创建全为false的二维数组

        ml = 1
        st = 0

        for i in range(n):#首先一个字符肯定是回文串
            dp[i][i]=True
        
        for j in range(1,n):
            for i in range(0,j):
                dp[i][j] = s[i] == s[j] and (i + 1 == j or dp[i+1][j-1]) #简洁代码写法
                """
                if s[i] == s[j]: 如果字符两头相同
                    if i + 1 == j:  如果此时字符串的长度为2
                        dp[i][j] = True
                    else:      否则就判断去掉两头之后的内部字符串
                        dp[i][j] = dp[i+1][j-1]
                """
                if dp[i][j] and j-i+1 > ml:#每次记得更新
                    ml = j-i+1
                    st = i
                
        return s[st:st+ml]

解法二:中心扩散法 O(N2)O(N^2)O(N2)
这个算是最容易想到的算法,要求回文串嘛,我们就找回文中心,然后判断以此中心能够构成的最长回文串,取最大值即可。关键在于回文串的奇偶长度,需要细心处理即可。复杂度就为O((2∗n−1)∗n)O((2*n-1)*n)O((2n1)n),还是O(n2)O(n^2)O(n2),可以接受的。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n < 2:
            return s
        nn = 2 * n - 1
        ml = 1
        st = 0
        for i in range (0, nn):
            l = 1
            k = i // 2
            j = 0
            if i % 2 != 0:
                l = 0
                while k - l >= 0 and k + l + 1 < n and s[k - l] == s[k + l + 1]:
                    l += 1
                j = k + 1 - l
                l *= 2
            else:
                while k - l >= 0 and k + l < n and s[k - l] == s[k + l]:
                    l += 1
                j = k + 1 - l
                l = 2 * l - 1

            if l > ml:
                st = j
                ml = l
        
        return s[st:st + ml]

解法三:Manacher 算法O(N)O(N)O(N)
目前没兴趣看,留着之后二刷的时候填坑吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值