[LeeCode] 5. Longest Palindromic Substring (Python)

5. Longest Palindromic Substring

Medium

6919537Add to ListShare

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

 

方法1:O(n^3)  暴力

从最长的子串(它本身)开始判断是否是回文,如果是则return,然后在判断长度减1的子串是否是回文。比如“babad”,先判断子串长度为5的所有子串是否是回文,如果是return,否则继续判断子串长度为4的所有子串是否是回文,如果某个子串是回文,则return

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        if length < 2:
            return s
        while length > 0:
            for i in range(len(s)):
                l, r = i, i + length
                if r <= len(s):
                    if self.isPalindrome(s[l:r]):
                        return s[l:r]
                else:
                    break
            length -= 1

    def isPalindrome(self, s: str):
        i, j = 0, len(s) - 1
        while i <= j:
            if s[i] == s[j]:
                i += 1
                j -= 1
            else:
                break
        if i > j:
            return True
        return False

 

方法2:O(n^2) 从中心向两边扩散

(1)将子串分为奇数串和偶数串

(2)从index=0开始一直到index=len(s) - 1, 奇数的时候left=index, right=index,如果s[left]==s[right],left减一,right加1知道不相等或者超出边界范围,同时比较当前满足回文的子串的长度与当前最长子串的长度,如果更长,则更新最长子串的长度。偶数的时候,left=index, right=index+1,剩下操作一样。我们以初始的s[index]看做子串的中间点,向两边扩散,当向两边扩散的时候偶数与奇数情况都要同时考虑

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        if length < 2:
            return s
        l , r = 0, 0
        def palindrome(s: str, left: int, right: int):
            nonlocal  l, r
            while left >= 0 and right < length and s[left] == s[right]:
                left -= 1
                right += 1
            if right - left - 1 > r - l + 1:
                l, r = left + 1, right - 1
        for i in range(length - 1):
            palindrome(s, i, i)
            palindrome(s, i, i + 1)
        return s[l:r + 1]

方法3:动态规划 O(n^2)

为了在验证回文的过程中减少不必要的比较,比如我们已经知道“bab”是一个回文,那么我们在判断"ababa"的时候,只需要比较左右两边的两个字母是否相同就可以了

注释掉的部分可以用一句代码替代

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        if length < 2:
            return s
        dp = [[False] * length for i in range(length)]
        rlt = ""
        for j in range(length):
            for i in range(j + 1):
                dp[i][j] = s[i] == s[j] and (j - i <= 2 or dp[i + 1][j - 1])
                # if i == j:
                #     dp[i][j] = True
                # elif j - i == 1:
                #     dp[i][j] = s[i] == s[j]
                # elif j - i > 1:
                #     dp[i][j] = s[i] == s[j] and dp[i + 1][j - 1]
                if dp[i][j]:
                    if j - i + 1 > len(rlt):
                        rlt = s[i:j + 1]
        return rlt

方法4: Manacher 算法 O(n)

参考 https://blog.csdn.net/Fly_Fly_Zhang/article/details/88780021

Manacher算法因为只有遇到没有匹配过的字符的时候,才去接着匹配,已经匹配过的字符不再匹配,所以对每个字符只进行匹配一次,所以时间复杂为O(2n + 1)=O(n)

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        if length < 2:
            return s
        new_s = "#"
        for letter in s:
            new_s += letter
            new_s += "#"
        Len = [0] * len(new_s)
        right = 0
        max_i = 0
        for i in range(len(new_s)):
            right = Len[max_i] + max_i - 1
            if i < right:
                j = 2 * max_i - i
                if i + Len[j] - 1 < right:
                    Len[i] = Len[j]
                else:
                    l, r = 2 * i - right, right
                    while l >= 0 and r < len(new_s) and l <= r and new_s[l] == new_s[r]:
                        l -= 1
                        r += 1
                    Len[i] = r - i
                    if Len[i] > Len[max_i]:
                        max_i = i
            else:
                l, r = i, i
                while l >= 0 and r < len(new_s) and l <= r and new_s[l] == new_s[r]:
                    l -= 1
                    r += 1
                Len[i] = r - i
                if Len[i] > Len[max_i]:
                    max_i = i
        rlt = ""
        for i in range(max_i - Len[max_i] + 1, max_i + Len[max_i]):
            if new_s[i] != "#":
                rlt += new_s[i]
        return rlt

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值