python实现寻找最长回文子串

Leetcode刷题笔记 专栏收录该内容
26 篇文章 1 订阅

题目描述

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

LeetCode原题地址:https://leetcode-cn.com/problems/longest-palindromic-substring/

测试用例

  • 示例 1

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

  • 示例 2

输入: “cbbd”
输出: “bb”

解题代码和思路

  • 遍历所有子串寻找回文子串
class Solution(object):
    def validate_palindrome(self,s,left,right):
        """判断字符串是否为回文字符串
        :param s:
        :param left:
        :param right:
        :return:
        """
        if len(s) < right and left < 0:
            assert("s length must greater than right,left must greater than or equal to zero")
        while left < right:
            #回文字符串左边和右边字符相等
            if s[left] != s[right]:
                return False
            #移动左边和右边的指针
            left += 1
            right -= 1
        return True


    def longestPalindrome(self,s):
        s_len = len(s)
        if s_len < 2:
            return s
        #用来记录回文字符串
        palindrome_s = s[0]
        #记录回文字符串长度
        max_len = 1
        #遍历字符串中的所有子串
        for i in range(s_len-1):
            for j in range(i+1,s_len):
                if j-i+1 > max_len and self.validate_palindrome(s,i,j):
                    palindrome_s = s[i:j+1]
                    max_len = j - i + 1

        return palindrome_s
  • 动态规划
class Solution(object):
    def longestPalindrome(self,s):
        size = len(s)
        #如果字符串的长度为1就是回文字符串
        if size < 2:
            return s
        #创建一个二维列表用来保存每个字符串是否为回文字符串
        is_p = [[False for _ in range(size)] for _ in range(size)]
        #对角线上都是回文字符串,因为都是单个字符
        for i in range(size):
            is_p[i][i] = True

        #用来记录回文字符串的起始位置
        s_index = 0
        max_len = 1
        #遍历表格,计算字符串是否为回文字符串
        for j in range(1,size):
            for i in range(0,j):
                if s[i] == s[j]:
                    if j - i < 3:
                        is_p[i][j] = True
                    else:
                        is_p[i][j] = is_p[i+1][j-1]
                else:
                    is_p[i][j] = False

                #记录最长的回文字符串
                current_len = j - i + 1
                if is_p[i][j] and current_len > max_len:
                    max_len = current_len
                    s_index = i
        return s[s_index:(s_index+max_len)]
  • 中心扩散算法
class Solution(object):
    def center_spread(self,s,size,left,right):
        """中心扩散寻找回文字符串
        :param s: 字符串
        :param size: 字符串的长度
        :param left: 开始寻找左边的位置
        :param right: 开始寻找右边的位置
        :return: 回文字符串,回文字符串的长度
        """
        i = left
        j = right
        #保证在寻找的过程中不发生越界,而且左右两个字符要相等
        while i >= 0 and j < size and s[i] == s[j]:
            i -= 1
            j += 1

        return s[i+1:j],j-i-1

    def longestPalindrome(self,s):
        size = len(s)
        if size < 2:
            return s
        s_palindrome = s[0]
        max_len = 0
        for i in range(size):
            #当回文字符串是奇数的时候
            odd_palindrome,odd_len = self.center_spread(s,size,i,i)
            #当回文字符串是偶数的时候
            even_palindrom,even_len = self.center_spread(s,size,i,i+1)
            #获取最长的回文字符串
            cur_palindrome = odd_palindrome if odd_len > even_len else even_palindrom
            #更新最长的回文字符串
            if len(cur_palindrome) > max_len:
                s_palindrome = cur_palindrome
                max_len = len(cur_palindrome)

        return s_palindrome
  • Manacher(拉马车) 算法
class Solution(object):
    def longestPalindrome(self,s):
        size = len(s)
        if size < 2:
            return s
        #对原始字符串的每个间隙添加一个字符串#
        expand_s = "#"
        for i in range(size):
            expand_s += s[i]
            expand_s += "#"
        #计算扩展之后的字符长度
        expand_s_size = size * 2 + 1
        #初始化P数组
        p = [0 for _ in range(expand_s_size)]
        #定义中心指针和右边界指针
        center = 0
        max_right = 0
        #记录最长回文字符串的起始位置
        start = 1
        #记录回文字符串的长度
        max_len = 1

        for i in range(expand_s_size):
            #利用回文字符的镜像特点,来减少重复的计算
            if i < max_right:
                mirror = 2 * center - i
                #利用镜像计算回文字符串的长度不能超过右边界
                p[i] = min(max_right-i,p[mirror])

            #定义左右两个指针,利用中心扩散算法寻找边界外的回文字符串
            left = i - (1 + p[i])
            right = i + (1 + p[i])
            while left < right and left >= 0 and right < expand_s_size and expand_s[left] == expand_s[right]:
                p[i] += 1
                left -= 1
                right += 1
            #更新最长的右边界和中心位置,尽量减少计算
            if p[i] > max_right:
                max_right = i + p[i]
                center = i
            #计算最长回文字符串
            if p[i] > max_len:
                max_len = p[i]
                start = (i - max_len) // 2

        return s[start:(start+max_len)]

参考:

  1. LeetCode详细题解
  2. 拉马车算法详解
  • 1
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏

修炼之路

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值