Bootstrap

动态规划1:最长回文子序列

问题描述:516. 最长回文子序列

给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。

示例 1:
输入:

"bbbab"
输出:

4
一个可能的最长回文子序列为 "bbbb"。

示例 2:
输入:

"cbbd"
输出:

2
一个可能的最长回文子序列为 "bb"。

方法一:斜线遍历

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [[0]*(n) for i in range(n)]
        
        for i in range(n):
            dp[i][i] = 1
        #l 为偏移量
        for l in range(1,n):
            for i in range(n-l):
                j = i + l
                if s[i] == s[j]:
                    dp[i][j] = dp[i+1][j-1]+2
                else:
                    dp[i][j] = max(dp[i+1][j],dp[i][j-1])
        
        return dp[0][n-1]

 

方法二:斜向下遍历+状态压缩

import copy
class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [1 for i in range(n)]
        pre = [0 for i in range(n)]
        tmp = [0 for i in range(n)]

        for l in range(1,n):
            for i in range(n-l):
                j = i + l
                //每次重新开启外循环时,l-1的元素要重新赋值,获得每次外循环开始的dp[i][j-1]元素
                //参考(0,1)(0,2)(0.3)(0,4)步骤  外循环新触发时元素的更新
                tmp[l-1] = dp[l-1] 
                //获得dp[i+1][j]
                tmp[j] = dp[j] 
                if s[i] == s[j]:
                    dp[j] = pre[j-1] + 2 //pre[j-1]就是dp[i+1][j-1]
                else:
                    dp[j] = max(tmp[j-1], tmp[j])
            //不能放在for内循环,因为每次都会更新pre数组,导致dp[i+1][j-1]被更新,参考(1,4)步骤
            pre = copy.deepcopy(tmp)
        return dp[n-1]

以测试集'bbbab'为例

l (i,j) tmp dp pre
1  (0, 1)  [1, 1, 0, 0, 0]  [1, 2, 1, 1, 1]  [0, 0, 0, 0, 0]
1  (1, 2)  [1, 1, 1, 0, 0]  [1, 2, 2, 1, 1]  [0, 0, 0, 0, 0]
1  (2, 3)  [1, 1, 1, 1, 0]  [1, 2, 2, 1, 1]  [0, 0, 0, 0, 0]
1  (3, 4)  [1, 1, 1, 1, 1]  [1, 2, 2, 1, 1]  [0, 0, 0, 0, 0]
2  (0, 2)  [1, 2, 2, 1, 1]  [1, 2, 3, 1, 1]
;