力扣 (LeetCode)刷题笔记5.最长回文子串 python

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
示例 3:
输入:s = “a”
输出:“a”
示例 4:
输入:s = “ac”
输出:“a”

提示:
1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring

这个题用Manacher算法进行求解。
首先给的字符串s可能有偶数个或者奇数个字符,为了统一操作,在字符串的空位间插入一个字符串中不会出现的字符,比如’*‘或者’#’。
比如abc变换后成为#a#b#c#

s = '#' + '#'.join(s) + '#'

创建RL数组,存储字符串第i个位置的回文半径。比如子串长度为5的话,回文半径就是2。
maxcenter为最长的回文中心。

while i-RL[i]-1>=0 and i+RL[i]+1<len(s) and s[i-RL[i]-1] == s[i+RL[i]+1]:
                RL[i] += 1   

如果以当前的字符串为回文中心的回文子串其向右向左都没有超出字符串的范围,即,i-RL[i]-1>=0 and i+RL[i]+1<len(s),且扩展后仍为回文子串,即s[i-RL[i]-1] == s[i+RL[i]+1],则当前点的回文半径+1。

if i+RL[i] > maxright:     
                maxright = RL[i] + i
                pos = i
if RL[i] > RL[maxcenter]:   
                maxcenter = i

if i+RL[i] > maxright,更新maxright和i。
if RL[i] > RL[maxcenter],更新maxcenter。
如果只考虑这些的话,也可以写出如下代码:

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        s = '*' + '*'.join(s) + '*'
        maxcenter = 0
        RL = [0] * len(s)

        for i in range(len(s)):

            RL[i] = 0
        
            while i - RL[i] - 1 >= 0 and i + RL[i] + 1 < len(s) and s[i - RL[i] - 1] == s[i + RL[i] + 1]:
                 RL[i] += 1

            if RL[i] > RL[maxcenter]:
                maxcenter = i

        return s[maxcenter - RL[maxcenter]:maxcenter + RL[maxcenter] + 1].replace('*','')

执行用时: 2416 ms
内存消耗: 13.1 MB
到这个地方还比较好懂,但是怎样高效地求的RL数组还需要考虑,因为前面的代码执行用时还是比较长的。
maxright代表目前所访问到的以这个字符串为回文中心的最右边界,pos为这个最右边界的回文中心的位置。maxright,pos都是为了高效地求的RL数组这个目的而设置的变量。
简单来说,就是利用前面已经求过的RL使得后面的RL少进行几次比较,就像KMP算法一样。
这个地方我参考一些博客想了好久才搞懂。
参考:
https://blog.csdn.net/xinxin100011/article/details/81235483?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161706754116780264077225%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=161706754116780264077225&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-9-81235483.first_rank_v2_pc_rank_v29&utm_term=最长回文子串+python

https://segmentfault.com/a/1190000003914228

for i in range(len(s)):
        if i<maxright:               #i在maxright左侧
            RL[i] = min(maxright-i, RL[pos*2-i] )	#(i+j)/2 = pos
        else:                      		 #i在maxright右侧(含)
            RL[i] = 0

完整代码如下:

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        s = '*' + '*'.join(s) + '*'
        pos = maxright = 0
        maxcenter = 0
        RL = [0] * len(s)

        for i in range(len(s)):
            if i < maxright:
                RL[i] = min(maxright - i,RL[2 * pos - i])
            else:
                RL[i] = 0
        
            while i - RL[i] - 1 >= 0 and i + RL[i] + 1 < len(s) and s[i - RL[i] - 1] == s[i + RL[i] + 1]:
                 RL[i] += 1
            if i + RL[i] > maxright:
                maxright = i + RL[i]
                pos = i
            if RL[i] > RL[maxcenter]:
                maxcenter = i

        return s[maxcenter - RL[maxcenter]:maxcenter + RL[maxcenter] + 1].replace('*','')

执行用时: 168 ms
内存消耗: 13 MB
这样一来,执行用时就大大减少了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值