2018-12-13 LeetCode Q5 最长回文子串

5 篇文章 0 订阅
5 篇文章 0 订阅

5. 最长回文子串

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

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

示例 2:
输入: "cbbd"
输出: "bb"

暴力解法(6004ms AC)
由最长的子串(本身)找起,当发现满足回文条件时返回结果。
维护当前子串长度 length
起始点由 0 到 距离尾部 length 的位置
根据起始点计算终点的索引,耗时很长,代码如下:

class Solution:
    def longestPalindrome(self, s):
        length = len(s)
        if length <= 1:
            return s
        while length > 0:
            for head in range(0, len(s)-length+1):
                tail = head+length
                if s[head:tail] == s[head:tail][::-1]:
                    return s[head:tail]
            length -= 1

巧妙解法(132ms AC)
其关键思想在于:
在发现一个回文子串 S j . . . S k S_j...S_k Sj...Sk的基础上,进入下一个字符 S k + 1 S_{k+1} Sk+1时,区分三种情况:

  • 当前字符和前一个回文子串构成一个新的回文子串 S j . . . S k + 1 S_j...S_{k+1} Sj...Sk+1
  • 当前字符和前一个回文子串以及子串的前一个字符构成新的回文子串 S j − 1 . . . S k + 1 S_{j-1}...S_{k+1} Sj1...Sk+1
  • 不构成新的回文子串,此时要查找的更长的回文子串长度应当为当前最长长度max_len+1 或 max_len+2

由于回文串在删去其头尾两端的字符时仍然是回文串,所以不必担心会遗漏结果。
在下面的代码中, i 始终控制查找的子串的结尾,目标是长度为 max_len+1 或者 max_len +2 的回文子串,当找到时,会进入情况一或情况二中,因此确保结果正确。

class Solution:
    def longestPalindrome(self, s):
        l=len(s)
        maxl=0
        start=0
        for i in range(l):
            # 情况二
            if i-maxl>0 and s[i-maxl-1:i+1]==s[i-maxl-1:i+1][::-1]:
                start=i-maxl-1
                maxl+=2
            # 情况一
            elif s[i-maxl:i+1]==s[i-maxl:i+1][::-1]:
                start=i-maxl
                maxl+=1
            # 情况三:什么也不做
        return s[start:start+maxl]

2019.03.16增补方法

类暴力法(2184ms AC)

与6000ms的方法不同,我们遍历两次中心点,第一次针对奇数长度的情况,第二次针对偶数长度的情况,当发现非回文序列子串时,则记下当前最长子串,并进入下一个中心点。

class Solution:
    def longestPalindrome(self, s):
        if len(s) <= 1:
            return s
        mid = 0
        tmp = s[0]
        for mid in range(0,len(s)):
            i = 1
            while mid - i >=0 and mid +i < len(s):
                if s[mid-i] == s[mid+i]:
                    if 2*i+1 > len(tmp):
                        tmp = s[mid-i:mid+i+1]
                    i += 1
                else:                
                    break
        for mid in range(0, len(s)):
            i = 1
            while mid - i >=0 and mid +i-1 < len(s):
                if s[mid-i] == s[mid+i-1]:
                    if 2*i > len(tmp):
                        tmp = s[mid-i:mid+i]
                    i += 1
                else:
                    break
        return (tmp)

类暴力法改进(124ms AC)

此方法在类暴力法的基础上只改进了一点,每次考虑新的子串时,从长度至少为max_length的中心开始比较。

class Solution:
    def longestPalindrome(self, s):
        if len(s) <= 1:
            return s
        mid = 0
        tmp = s[0]
        for mid in range(0,len(s)):
            i = len(tmp)//2 # 仅在这里进行调整
            while mid - i >=0 and mid + i < len(s):
                if s[mid-i:mid+i+1] != s[mid-i:mid+i+1][::-1]:
                    break
                else:
                    if 2*i+1 > len(tmp):
                        tmp = s[mid-i:mid+i+1]
                    i += 1
        for mid in range(0, len(s)):
            i = len(tmp)//2
            while mid - i >=0 and mid +i-1 < len(s):
                if s[mid-i:mid+i] != s[mid-i:mid+i][::-1]:
                    break
                else:
                    if 2*i > len(tmp):
                        tmp = s[mid-i:mid+i]
                    i += 1
        return (tmp)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值