动态规划:最长回文子串

目录

题目

思路

解题过程

复杂度

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]

  • 15
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最长回文子串是指在一个字符串中最长的回文子序列。回文是指正着读和倒着读都一样的字符串。动态规划是解决最长回文子串问题的一种常用方法。动态规划的思想是将问题分解成子问题,通过求解子问题的最优解来得到原问题的最优解。在最长回文子串问题中,我们可以使用一个二维数组dp[i][j]来表示从i到j的子串是否为回文子串。如果dp[i][j]为true,则表示从i到j的子串是回文子串,否则不是。我们可以通过以下步骤来求解最长回文子串: 1. 初始化dp数组,将所有dp[i][i]都设置为true,表示单个字符是回文子串。 2. 遍历字符串s,从长度为2的子串开始,依次判断每个子串是否为回文子串。如果是,则将dp[i][j]设置为true。 3. 在遍历的过程中,记录最长回文子串的长度和起始位置。 4. 最后,通过起始位置和长度来截取最长回文子串。 下面是一个示例代码,可以帮助你更好地理解动态规划求解最长回文子串的过程: class Solution { public: string longestPalindrome(string s) { int len=s.size(); if(len<2) return s; bool dp[len][len];//布尔型,dp[i][j]表示从i到j是否构成回文 int max_count=1;//最大字串的长度 int start=0;//最长字串的起始位置 for(int j=0;j<len;j++) { for(int i=0;i<j;i++) { if(s[i]!=s[j]) dp[i][j]=false; else if((j-i)<3)//(j-1)-(i+1)+1<2表示dp[i][j]的最大字串长度为1 dp[i][j]=true; else { dp[i][j]=dp[i+1][j-1]; } if((j-i+1)>max_count&&dp[i][j]) { max_count=j-i+1; start=i; } } } return s.substr(start,max_count);//截取字符串 } };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值