动态规划:最长回文子串

目录

题目

思路

解题过程

复杂度

code 


题目

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

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

思路

        使用动态规划方法来解决最长回文子串问题。动态规划通过构建一个表格来存储中间结果,避免重复计算,从而提高效率。


解题过程

  • 初始化

  1. 创建一个 n×n 的布尔表 dpdp[i][j] 表示子串 s[i:j+1] 是否为回文。
  2. 初始化这个二维表。对于长度为1的子串(即单个字符),它们自然是回文串,因此dp[i][i](所有对角线上的元素)都应该被设置为True
    n = len(s)  

	dp = [[False] * n for _ in range(n)]  

	for i in range(n):  

	    dp[i][i] = True
  • 填表

  1. 回文子串的长度可以从2开始逐渐增加,可以从长度为2的子串开始检查,然后是长度为3的子串,依此类推,直到长度为n的子串。对于每个长度,我们遍历所有可能的起始索引
  2. 对于任意dp[i][j](其中i < j),如果s[i] == s[j](即子串的两个端点字符相同),我们需要检查子串内部(即s[i+1:j])是否也是回文串。这可以通过查看dp[i+1][j-1]的值来实现。如果dp[i+1][j-1]True,则dp[i][j]也为True此外,对于长度为2或3的子串,我们可以直接通过比较字符来判断,而无需检查内部子串,因为这样的子串要么只包含两个相同的字符(长度为2),要么包含三个字符且首尾相同、中间字符任意(长度为3,但首尾相同的情况已经通过比较字符确定了)。
for length in range(2, n+1):  # 子串长度从2到n  

	    for i in range(n - length + 1):  # 遍历所有可能的起始索引  

	        j = i + length - 1  # 计算结束索引  

	        if s[i] == s[j] and (length == 2 or dp[i+1][j-1]):  

	            dp[i][j] = True
  • 更新最长回文子串的起始位置和长度:

         在填表的过程中,我们还需要跟踪记录到目前为止找到的最长回文子串的起始位置和长度。这可以通过比较当前回文子串的长度和已记录的最长长度来实现,并在需要时更新这些信息

max_length = 1  
start = 0  
for length in range(2, n+1):  
    for i in range(n - length + 1):  
        j = i + length - 1  
        if dp[i][j] and length > max_length:  
            max_length = length  
            start = i
  • 结果提取

      根据记录的最长回文子串的起始位置和长度,从原字符串中提取出这个子串作为结果

longest_palindrome = s[start:start+max_length]

复杂度

  • 时间复杂度: O(n^2),要检查字符串中所有可能的子串(即从每个索引开始,长度为2到n的所有子串),这导致了一个双重循环,每层循环都遍历了字符串的一部分。
  • 空间复杂度: O(n^2),因为需要一个 n×n 的布尔表来存储每个子串是否为回文的状态。

code 

class Solution(object):
    def longestPalindrome(self, s):
        if len(s) < 2:
            return s

        n = len(s)
        max_len = 1
        start = 0
        dp = [[False] * n for _ in range(n)]

        for i in range(n):
            dp[i][i] = True

        for j in range(1, n):
            for i in range(0, j):
                if s[i] == s[j]:
                    if j - i < 3:
                        dp[i][j] = True
                    else:
                        dp[i][j] = dp[i + 1][j - 1]

                if dp[i][j] and j - i + 1 > max_len:
                    max_len = j - i + 1
                    start = i

        return s[start:start + max_len]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值