Leetcode [Longest Palindromic Substring]

Problem:Longest Palindromic Substring

Question

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

思路

Manacher算法

对于一个字符串,除了直接遍历以外,也可以用扩展的方式来找字符串
怎么扩展呢, 以 ababa 为例子

char: a b a b a
pos : 0 1 2 3 4
  1. 遍历这个字符串,在每个位置,依次向两边拓展,如果不超出边界,而且是回文的则继续拓展直到碰到边界或者不能回文为止。如果越界或者不回文,那就拓展下一个位置
  2. 字符串的“空隙”(两个字符之间的位置)也是必须拓展的
  3. 记录遍历期间拓展到的最长的长度和位置,就可以得到最长的回文字符串

比如在 1 位置上,b字母向左右两边拓展,可以得到aba,是回文的,继续拓展,左边会越界,所以就暂停拓展,这个位置最长的回文字符串就是 “aba”。但容易发现,遍历的时候有些子串会被遍历超过两次。
比如在 1 位置和 2 位置,左边的“aba”会被遍历两次(2位置的最长回文串是ababa,可想而知必须拓展到 0 位置的a)。降低算法效率。
另外,这个字符串的“空隙”还要自己去定义,存在奇偶性问题。
Manacher算法解决了这两个缺陷
Manacher算法主要做的事情:

  1. 在字符串的首尾和空隙插入没有在原串中出现的相同的字符,使得新的字符串是奇数长度
  2. 维护一个回文半径数组,解决重复访问的问题。
  3. 记录当前可回文字符串中最右的位置Maxright以及对应的对称轴的位置pos

举个栗子

ababa -> #a#b#a#b#a#
char: # a # b # a # b # a #
RL[]: 1 2 1 3 1 6 1 3 1 2 1
// 回文半径是当前位置可以看成可拓展的最长长度加一

这样带来的好处有:

  • 不影响原字符串回文,而且用同样的字符代替空隙,解决对称轴的问题
  • 解决重复访问的问题,提高效率

Maxright 和 pos有什么作用?
看下图,也就是解决重复访问问题

某种情况下的Maxright

具体的讲解,可以到这个专栏看一下

解题代码

class Solution(object):
    def longestPalindrome(self, s):
        s = '#' + '#'.join(s) + '#'
        pos = 0
        maxright = 0
        RL = [0] * len(s)
        maxIndex = 0
        maxlen = 0
        for i in range(len(s)):
            if i < maxright:
                RL[i] = min(RL[2*pos-i], maxright - i)
            else:
                RL[i] = 1
            start = i - RL[i]
            end = i + RL[i]
            while start >= 0 and end < len(s) and s[start] == s[end]:
                RL[i] += 1
                start = i - RL[i]
                end = i + RL[i]
            if i + RL[i] - 1 > maxright:
                maxright = i + RL[i] - 1
                pos = i
            if RL[i] > maxlen:
                maxlen = RL[i]
                maxIndex = i
        maxright = maxIndex + RL[maxIndex] - 1
        maxleft = 2*maxIndex - maxright
        return ''.join(s[maxleft : maxright].split('#'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值