leetcode5 最长回文子串

解法1:中心扩散
简单,不提

解法2:动态规划,从上往下填表很重要

import numpy as np

class Solution:
    def longestPalindrome(self, s: str) -> str:
        dp = np.zeros((len(s), len(s)))
        
        l_str = s[0]
        l_len = 1

        # 状态转移
        for i in range(len(s)):
            dp[i][i] = 1 # 填对角线
            for j in range(i):
                if s[i] == s[j] and (dp[j+1][i-1] == 1  or i == j+1):
                    dp[j][i] = 1
                    if i-j+1 > l_len:
                        l_len = i-j+1
                        l_str = s[j:i+1]

        return l_str

上述解法有个优化:记录时不必记录整个回文串,记录起始位置即可,这样可以省去访问时间,最后返回时访问即可。
优化2:使用python list创建二维数组,时间会快很多

dp = [[0 for _ in range(len(s))] for _ in range(len(s))]

解法3:马拉车算法
用中心扩散解法很容易获得以每个元素为中心的最大扩展长度,把他们记录在数组中,取最大就能的到结果。但每次都重复计算很伤。马拉车利用了前面计算的信息来减少运算,最终实现O(N)的复杂度。如何利用前面的信息呢?答案是对称性,kmp算法也是利用前面的计算和实际数组前后相同来做。本算法维护一个最远对称窗口,记录最右扩展的点以及中心。包含在这一窗口内,右边未计算的点可以利用左边的对称信息来解,因为他们的回文程度相同。
如果dp[mirror]的长度超过了maxRight,那么长度一定等于maxRight - i,因为左边边界外元素,回文元素,mirror对应元素都是相同的,而右边maxRight右边的和这三个不可能相同。如果dp[mirror]的长度正好等于maxRight,则需要继续往外扩散看最大长度。这种情况最左边两个元素不一定相同,所以maxRight+1是可能继续回文的。
如果i >= maxRight,左边元素是给不到任何回文信息的,因为左右在边界处不对称。

import numpy as np
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s) < 1: return s
        ss = "#"
        for c in s:
            ss += c + '#'

        maxRight, center = 0, 0
        dp = [0 for _ in ss]

        def expand(i, j, maxRight, center):
            while i+j < len(ss) and ss[i+j] == ss[i-j]:
                j += 1
            if i+j-1 > maxRight:
                maxRight = i+j-1
                center = i
            dp[i] = j-1
            return maxRight, center

        for i, c in enumerate(ss):
            mirror = 2*center - i
            if i >= maxRight or mirror < 0: 
                maxRight, center = expand(i, 1, maxRight, center)
            elif dp[mirror] < maxRight-i:
                dp[i] = dp[mirror]
            elif dp[mirror] > maxRight-i:
                dp[i] = maxRight-i
            else:
                maxRight, center = expand(i, dp[mirror]+1, maxRight, center)

        i = np.argmax(dp)
        if dp[i] == 0: return s[0]
        ret = ''
        for j in range(i-dp[i], i+dp[i]+1):
            if ss[j] != '#':
                ret += ss[j]
        return ret
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值