LeetCode_5 Longest Palindromic Substring

最优解 Manacher

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”

思路一:
暴力法!通过始、终索引 i,j穷举所有可能的子串,判断子串是否为回文,使用 length变量记录最大回文子串的长度,若新的回文子串长度大于当前的 length则更新 length,并记录当前子串的起始索引。最终通过索引返回最长回文子串。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = left = right =0
        n = len(s)
        if n<=1: return s
        for i in range(n):
            for j in range(i+1, n+1):
                sub = s[i:j]
                if length < j-i and sub == sub[::-1]:
                    left,right = i,j
                    length = j-i
        return s[left:right]

结果:
在这里插入图片描述

分析:

  • 时间复杂度: O ( n 3 ) O(n^3) O(n3), 假设 n n n 是输入字符串的长度,则 C n 2 = n ( n − 1 ) / 2 C_n^2 = n(n-1)/2 Cn2=n(n1)/2 为子字符串的总数。验证每个子字符串需要 O ( n ) O(n) O(n)的时间,所以运行时间复杂度是 O ( n 3 ) O(n^3) O(n3)
  • 空间复杂度: O ( 1 ) O(1) O(1)

思路二:
中心扩展方法。我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2 n − 1 2n-1 2n1个这样的中心。

你可能会问,为什么会是 2 n − 1 2n-1 2n1个,而不是 n n n个中心?原因在于所含字母数为偶数的回文的中心可以处于两字母之间(例如 &quot; a b b a &quot; &quot;abba&quot; "abba"的中心在两个 &quot; b &quot; &quot;b&quot; "b"之间)。
接下来的关键就是对边界的把握,确保下标不要越界。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        max_len = start = end = 0
    
        for i in range(length):
            len1 = self.expand(s, i, i) #奇数中心扩散,判断该中心点的最大回文长度
            len2 = self.expand(s, i, i+1) #偶数中心扩散
            max_len = max(len1, len2)
            if max_len > end-start:
                start = i - (max_len -1)//2
                end = i + max_len//2
        return(s[start:end+1])
    
    def expand(self, s, l, r):
        while l >= 0 and r < len(s) and s[l] == s[r]:
            l -= 1
            r += 1
        return r-l-1

结果:

在这里插入图片描述

分析:
时间复杂度: O ( n 2 ) O(n^2) O(n2),遍历中心复杂度为 O ( n ) O(n) O(n),对于每个中心,从中心展开的时间复杂度为 O ( n ) O(n) O(n),所以总的时间复杂度为 O ( n 2 ) O(n^2) O(n2).
空间复杂度: O ( 1 ) O(1) O(1).

思路三: Manacher algorithm (马拉车算法)
1). 中心展开法需要按照子串长度的奇偶,分情况处理子串。为了统一,Manacher算法在每个字符的两端插入一个特殊符号比如 “#”,这个符号必须 not in s(插入相同特殊符号并不会影响回文性质,且最终返回的最长回文子串一定以#开始、以#结束)所以最终返回子串的时候的索引可以有变动~~~

比如,原字符串 s = "google", 进行过插入特殊符号后,字符串由 t 表示:t = "#g#o#o#g#l#e#", 这样处理后的字符串总长度总是奇数,因为插入 “#” 的个数等于原字符串长度加一。这就巧妙的避免了要分情况处理子串。

2). 计算半径数组p
数组p指对于每个位置i,存在的最长半径p[i],使得t[i-p[i],i+p[i]]是回文子串。

若是贪婪算法,需要对每个i,初始化p[i]=0,然后递增p[i]直至找出以i为中心的最长回文子串t[i-p[i],i+p[i]]

Manacher的精髓:使用已求出的位置j对应的最大半径p[j],作为现在要求的位置i对应的p[i]的下界。

怎么计算p[i]呢? Manacher算法增加两个辅助变量: center和rear,表示已知的、以 center 为中心的最长回文子串的半径是rear, 且rear = p[center].

Manacher的精髓就在于此: 当rear>i时,p[i]有一个最小值p[j].if rear>i: p[i] = min(P[j],rear-i])rear-i>0rear>ip[i] = max(0, min(rear-i, p[j])),其中j = center - (i - center), j是i关于center的对称.
从对称角度看,以j为中心、p[j]为半径的回文子串应当与以i为中心的字符相等,至少在半径rear-i内是相等的。于是,p[j]就相当于p[i]的一个下界。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s) < 2: return s
        t = "^#" + '#'.join(s) + '#$' #拓展s,使得每个字符的下标都是偶数
        center = rear = 0 #center回文子串的中心,rear 回文子串的结尾下标
        p = [0]*len(t) # p[i] 对于每个字符作为中心,扩展的最长回文子串的半径
        
        for i in range(1, len(t)-1):
            mirror = center - (i - center) # i 关于center的对称
            p[i] = max(0, min(rear-i, p[mirror])) # 重点
            while t[i + p[i] + 1] == t[i - p[i] - 1]: # 以i为中心拓展
                p[i] += 1
            if p[i] + i > rear: # 更新中心点和子串结尾下标
                center = i
                rear = p[i] + i
        k,i = max((p[i],i) for i in range(1, len(t)-1)) #获取回文子串最长半径
        return s[(i-k)//2:(i+k)//2]

结果:
在这里插入图片描述

分析:
时间复杂度: O ( n ) O(n) O(n),从左到右遍历全部字符,构建数组p,利用已经求出的p[j]来求p[i],时间复杂度呈线性。
空间复杂度: O ( n ) O(n) O(n),额外的数组p

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值