leetcode--5. 最长回文子串:动态规划——状态转移方程

文章介绍了如何使用动态规划方法解决找到字符串中最长回文子串的问题,通过定义状态、边界条件和状态转移方程,实现算法优化,减少了空间复杂度。给出的两个Python代码示例展示了具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解题思路
动态规划:填dp表、当前ij状态、过去ij状态、如何联合得到输出、边界条件
1.定义状态:题目让我们求什么,就把什么设置为状态。

2.题目求s中最长的回文子串,那就判断所有子串是否为回文子串,选出最长的。
因此:dp[i][j]表示s[i:j+1]是否为回文子串(这里+1是为了构造闭区间)
状态转移方程:对空间进行分类讨论(当前ij状态、过去ij状态 如何联合得到输出)
当前ij状态:头尾必须相等(s[i]==s[j])
过去ij状态:去掉头尾之后还是一个回文(dp[i+1][j-1] is True)
边界条件:只要是找过去ij状态的时候,就会涉及边界条件(即超出边界情况处理)

当i==j时一定是回文
j-1-(i+1)<=0,即j-i<=2时,只要当s[i]==s[j]时就是回文,不用判断dp[i+1][j-1]
dp[i][j] 为截取的子串

3.初始状态:这里已经直接判断j-i<=2的情况了,因此用不到初始状态,可以不设

4.输出内容:每次发现新回文都比较一下长度,记录i与长度

5.优化空间提速

例子
在这里插入图片描述
代码

class Solution:
    def longestPalindrome(self, s: str) -> str:
        
        size = len(s)
        # 特殊处理
        if size == 1:
            return s
        # 创建动态规划dynamic programing表
        dp = [[False for _ in range(size)] for _ in range(size)]
        # 初始长度为1,这样万一不存在回文,就返回第一个值(初始条件设置的时候一定要考虑输出)
        max_len = 1
        start = 0
        for j in range(1,size):
            for i in range(j):
                # 边界条件:
                # 只要头尾相等(s[i]==s[j])就能返回True
                if j-i<=2:
                    if s[i]==s[j]:
                        dp[i][j] = True
                        cur_len = j-i+1
                # 状态转移方程 
                # 当前dp[i][j]状态:头尾相等(s[i]==s[j])
                # 过去dp[i][j]状态:去掉头尾之后还是一个回文(dp[i+1][j-1] is True)
                else:
                    if s[i]==s[j] and dp[i+1][j-1]:
                        dp[i][j] = True
                        cur_len = j-i+1
                # 出现回文更新输出
                if dp[i][j]:
                    if cur_len > max_len:
                        max_len = cur_len
                        start = i

        return s[start:start+max_len]

作者:_Breiman
链接:https://leetcode.cn/problems/longest-palindromic-substring/solution/5-zui-chang-hui-wen-zi-chuan-dong-tai-gu-p7uk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
def longestPalindrome(self, s: str) -> str:
        n = len(s)

        # 特解
        if n < 2:
            return s

        '''
        创建动归表dp (n x n的全为False的矩阵) 用来表示字符串s的每一个子串是否为回文
        s子串个数 = n + n - 1 + ... + 1, e.g. 字符串babad有5 + 4 + 3 + 2 + 1 = 15种子串
        start用来跟踪最长回文子串的起点, max_len代表最长回文子串的长度
        '''
        dp = [[False] * n for _ in range(n)]
        start, max_len = 0, 1

        '''
        如果字符串是babad
        下面的双循环则进行以下遍历 (遍历所有可能的15个子字符串):
        b
        ba,    a
        bab,   ab,   b,
        baba,  aba,  ba,  a
        babad, abad, bad, ad, d

        dp[left][right]代表s被left和right指针相夹而得的子字符串
        e.g. left = 0, right = 3, dp[left][right] = baba
        '''
        for right in range(n):
            for left in range(0, right + 1):
                '''
                (0) 求子串跨越长度span
                (1) 边缘情况1: 子串长度为1, 则一定是回文
                (2) 边缘情况2: 子串长度为2, 如果俩字符相同则是回文
                (3) 非边缘情况则进行动态规划之状态转移: 如果b是回文, aba也一定是回文
                    即判断是否为回文需同时满足两条件: 
                        1. 剥离左右最外层字符后的子字符串是回文 
                        2. 最外层的字符相同
                '''
                span = right - left + 1
                if span == 1:
                    dp[left][right] = True
                elif span == 2:
                    dp[left][right] = s[left] == s[right]
                else:
                    dp[left][right] = dp[left + 1][right-1] and s[left] == s[right]

                # 若新的回文出现, 判断是否需要更新最大长度
                if dp[left][right]:
                    if span > max_len:
                        max_len = span
                        start = left
        # 返回最长回文子串
        return s[start:start + max_len]

作者:eason734
链接:https://leetcode.cn/problems/longest-palindromic-substring/solution/zui-tong-su-wu-fei-hua-de-pythondong-tai-nysh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值