最长回文子串--动态规划

问题来源最长回文子串

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

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

1. O ( n 3 ) O(n^3) O(n3)算法

最简单也是最直观的做法是暴力算法。通过两层遍历,我们可以选出所有可能的子串,然后判断该子串是否是回文。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        max_huiwen = ''
        for i in range(len(s)):
            for j in range(i+1, len(s)+1):
                # 判断s[i:j]是否是回文
                ss = s[i:j]
                if ss == ss[::-1]:
                    if len(max_huiwen) < len(ss):
                        max_huiwen = ss
        return max_huiwen

这种算法注定用时最长,可能超时。

2. O ( n 2 ) O(n^2) O(n2)算法

暴力算法实际上重复判断了很多子串,比如,我们判断“abcba”是否为回文,我们不但判断子串“abcba”是否为回文,也判断子串“bcb”是否为回文。实际上,我们在判断子串“bcb”是回文之后,应该保留这种信息,然后判断子串“abcba”是否为回文。

我们需要判断每个较小的子串是否为回文,基于此,我们进一步判断较长子串是否为回文。

动态规划适用条件是,该问题较大规模问题可以由较小问题解决,以及该问题有最优子结构,也就是说,该问题的最优解中包含子问题的最优解。可以看到,判断子串是否为回文,可以分解为子串的子串是否为回文。

动态规划有三点:状态定义状态转移方程边界值

  • 状态定义: d ( i , j ) d(i, j) d(i,j)存储bool值,用于判断子串s[i, j+1]是否为回文;
  • 状态转移方程: d ( i , j ) = ( s [ i ] = = s [ j ] )  and  d ( i + 1 , j − 1 ) d(i, j) = (s[i]==s[j])~ \text{and}~ d(i+1, j-1) d(i,j)=(s[i]==s[j]) and d(i+1,j1),意思是,字符串s[i, j+1]是否为回文,取决于1)字符串左右两端字符是否相等,即s[i]==s[j];且2)子串s[i+1, j-1]是否为回文;
  • 边界值:如果j==i,则 d ( i , j ) = True d(i, j)=\text{True} d(i,j)=True;如果j==i+1,那么只需判断字符串两端是否相同;如果j>=i+2,那么用状态转移方程判断

具体代码如下:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        d = [[False for i in range(len(s))] for j in range(len(s))]

        # 子串长度i从1(自身)到len(s)
        for i in range(len(s)):
            # 给定长度i,子串从j开始
            for j in range(len(s)-i):
                if i == 0: # 子串长度为1
                    d[j][j+i] = True
                elif i == 1: # 子串长度为2
                    d[j][j+i] = (s[j] == s[j+i])
                else: # 子串长度为3及以上
                      # 长度为i的子串变成长度为i-2的子串
                    d[j][j+i] = (s[j] == s[j+i]) and d[j+1][j+i-1] 
        #print(d)
        # 在二维数组d中,寻找值为True且col-row最大的项
        max_item = -1
        start, end = -1, len(s)
        for i in range(len(s)):
            for j in range(len(s)):
                if d[i][j] and j - i > max_item:
                    max_item = j - i
                    start, end = i, j
        return s[start:end+1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值