leetcode 5.最长回文子串

此题有多种方法

暴力解法

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        maxLen = 0
        maxString = ""

        if length <= 1:
            return s

        for i in range(length):
            for j in range(i+1,length+1):
                seq = s[i:j]
                rev = seq[::-1]
                if seq == rev:
                    if len(seq) > maxLen:
                        maxLen = len(seq)
                        maxString = seq
                    
        return maxString

动态规划法

方法三:动态规划(推荐)

推荐理由:暴力解法太 naive,中心扩散不普适,Manacher 就更不普适了,是专门解这个问题的方法。而用动态规划我认为是最有用的,可以帮助你举一反三的方法。

补充说明:Manacher 算法有兴趣的朋友们可以了解一下,有人就借助它的第一步字符串预处理思想,解决了 LeetCode 第 4 题。因此以上推荐仅代表个人观点。

解决这类 “最优子结构” 问题,可以考虑使用 “动态规划”:

1、定义 “状态”;
2、找到 “状态转移方程”。

记号说明: 下文中,使用记号 s[l, r] 表示原始字符串的一个子串,lr 分别是区间的左右边界的索引值,使用左闭、右闭区间表示左右边界可以取到。举个例子,当 s = 'babad' 时,s[0, 1] = 'ba' ,s[2, 4] = 'bad'

1、定义 “状态”,这里 “状态”数组是二维数组。

dp[l][r] 表示子串 s[l, r](包括区间左右端点)是否构成回文串,是一个二维布尔型数组。即如果子串 s[l, r] 是回文串,那么 dp[l][r] = true

2、找到 “状态转移方程”。

首先,我们很清楚一个事实:

1、当子串只包含 1 个字符,它一定是回文子串;

2、当子串包含 2 个以上字符的时候:如果 s[l, r] 是一个回文串,例如 “abccba”,那么这个回文串两边各往里面收缩一个字符(如果可以的话)的子串 s[l + 1, r - 1] 也一定是回文串,即:如果 dp[l][r] == true 成立,一定有 dp[l + 1][r - 1] = true 成立。

根据这一点,我们可以知道,给出一个子串 s[l, r] ,如果 s[l] != s[r],那么这个子串就一定不是回文串。如果 s[l] == s[r] 成立,就接着判断 s[l + 1] 与 s[r - 1],这很像中心扩散法的逆方法。

事实上,当 s[l] == s[r] 成立的时候,dp[l][r] 的值由 dp[l + 1][r - l] 决定,这一点也不难思考:当左右边界字符串相等的时候,整个字符串是否是回文就完全由“原字符串去掉左右边界”的子串是否回文决定。但是这里还需要再多考虑一点点:“原字符串去掉左右边界”的子串的边界情况。

1、当原字符串的元素个数为 3 个的时候,如果左右边界相等,那么去掉它们以后,只剩下 1 个字符,它一定是回文串,故原字符串也一定是回文串;

2、当原字符串的元素个数为 2 个的时候,如果左右边界相等,那么去掉它们以后,只剩下 0 个字符,显然原字符串也一定是回文串。

把上面两点归纳一下,只要 s[l + 1, r - 1] 至少包含两个元素,就有必要继续做判断,否则直接根据左右边界是否相等就能得到原字符串的回文性。而“s[l + 1, r - 1] 至少包含两个元素”等价于 l + 1 < r - 1,整理得 l - r < -2,或者 r - l > 2

综上,如果一个字符串的左右边界相等,以下二者之一成立即可: 1、去掉左右边界以后的字符串不构成区间,即“ s[l + 1, r - 1] 至少包含两个元素”的反面,即 l - r >= -2,或者 r - l <= 2; 2、去掉左右边界以后的字符串是回文串,具体说,它的回文性决定了原字符串的回文性。

于是整理成“状态转移方程”:

dp[l, r] = (s[l] == s[r] and (l - r >= -2 or dp[l + 1, r - 1]))
class Solution:
    def longestPalindrome(self, s: str) -> str:
        size = len(s)
        if size <= 1:
            return s
        
        dp = [[False for _ in range(size)] for _ in range(size)]

        max_len = 1
        res = s[0]

        for r in range(1, size):
            for l in range(r):
                if s[l] == s[r] and (r-l <=2 or dp[l+1][r-1]):
                    dp[l][r] = True
                    cur_len = r - l + 1
                    if cur_len > max_len:
                        max_len = cur_len
                        res = s[l:r+1]

        return res

相关推荐

  1. LeetCode-5

    2024-03-19 12:38:05       50 阅读
  2. 【Manacher】LeetCode-5.

    2024-03-19 12:38:05       56 阅读
  3. LeetCode_5_中等_

    2024-03-19 12:38:05       57 阅读
  4. leetcode 5.

    2024-03-19 12:38:05       45 阅读
  5. leetcode 5, Manachers算法

    2024-03-19 12:38:05       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-19 12:38:05       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-19 12:38:05       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-19 12:38:05       87 阅读
  4. Python语言-面向对象

    2024-03-19 12:38:05       96 阅读

热门阅读

  1. 配置lvs(DR)

    2024-03-19 12:38:05       37 阅读
  2. MySQL常用命令总结

    2024-03-19 12:38:05       42 阅读
  3. ElasticSearch初识

    2024-03-19 12:38:05       35 阅读
  4. pytorch升级打怪(八)

    2024-03-19 12:38:05       42 阅读
  5. 机器视觉系统选型-选型&标定&通信

    2024-03-19 12:38:05       41 阅读
  6. 一个经典的wordpress产品列表模板含CSS样式

    2024-03-19 12:38:05       42 阅读