• 516. 最长回文子序列


    516. 最长回文子序列

    题目链接:516. 最长回文子序列(中等)

    给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

    子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

    示例 1:

    输入:s = "bbbab"
    输出:4
    解释:一个可能的最长回文子序列为 "bbbb" 。

    示例 2:

    输入:s = "cbbd"
    输出:2
    解释:一个可能的最长回文子序列为 "bb" 。

    提示:

    • 1 <= s.length <= 1000

    • s 仅由小写英文字母组成

    解题思路

    注意本题与647. 回文子串 的不同:回文子串是要连续的,回文子序列可不是连续的!

    求回文子串和回文子序列都是动态规划的经典题目。

    1. dp数组的含义

      dp[i][j]表示字符串s[i,j]范围内最长的回文子序列的长度。

    2. 递推公式

      关键看s[i]s[j]是否相同

      • s[i] == s[j],那dp[i][j]就等于字符串s[i+1,j-1]范围内最长的回文子序列的长度加上字符s[i]s[j]。即:dp[i][j]=dp[i+1][j-1]+2

      • s[i] != s[j],那就考虑在s[i+1,j-1]的基础上加入左边的字符s[i]或右边的字符s[j]所能得到的最长长度。

        • 加入左边的字符s[i]dp[i][j]=dp[i][j-1]

        • 加入右边的字符s[j]dp[i][j]=dp[i+1][j]

        取两者的最大值:dp[i][j]=max(dp[i][j-1],dp[i+1][j])

    3. dp的初始化

      首先考虑i = j ,从递推公式:dp[i][j]=dp[i+1][j-1]+2可以看出:递推公式是计算不到 ij相同时的情况。所以需要手动初始化一下:当i=j,那么dp[i][j]一定是等于1的,即:一个字符的回文子序列长度就是1。

      其他情况dp[i][j]初始为0就行,这样递推公式:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])dp[i][j]才不会被初始值覆盖。

    4. 遍历顺序

      从递推公式来看,遍历i的时一定要从下到上遍历,遍历j时一定要从左到右遍历。

    C++

    class Solution {
    public:
        int longestPalindromeSubseq(string s) {
            vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
            for (int i = 0; i < s.size(); i++) {
                dp[i][i] = 1;
            }
            for (int i = s.size() - 1; i >= 0; i--) {
                for (int j = i + 1; j < s.size(); j++) {
                    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][s.size() - 1];
        }
    };

    JavaScript

    /**
     * @param {string} s
     * @return {number}
     */
    var longestPalindromeSubseq = function(s) {
        const dp = new Array(s.length).fill().map(item => Array(s.length).fill(0));
        for (let i = 0; i < s.length; i++) {
            dp[i][i] = 1;
        }
        for (let i = s.length - 1; i >= 0; i--) {
            for (let j = i + 1; j < s.length; j++) {
                if (s[i] == s[j]) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[0][s.length - 1];
    };

     

     

  • 相关阅读:
    设计模式——设计原则与思想总结
    SQL——性能优化篇(下)
    计算机组成原理——入门篇
    SQL——性能优化篇(中)
    SQL——性能优化篇(上)
    设计模式——规范与重构(下)
    设计模式——规范与重构(上)
    编译原理——实现一门脚本语言 应用篇
    编译原理——实现一门脚本语言 原理篇(下)
    设计模式——设计原则实战
  • 原文地址:https://www.cnblogs.com/wltree/p/16043343.html
Copyright © 2020-2023  润新知