( 动态规划) 516. 最长回文子序列 ——【Leetcode每日一题】

这篇具有很好参考价值的文章主要介绍了( 动态规划) 516. 最长回文子序列 ——【Leetcode每日一题】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

❓516. 最长回文子序列

难度:中等

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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= s.length <= 1000
  • s 仅由小写英文字母组成

💡思路:动态规划

对于一个子序列而言,如果它是回文子序列,并且长度大于 2,那么将它首尾的两个字符去除之后,它仍然是个回文子序列。因此可以用动态规划的方法计算给定字符串的最长回文子序列。

定义二维dp数组,dp[i][j] 表示字符串 s 的下标范围 [i,j] 内的最长回文子序列的长度。假设字符串 s 的长度为 n,则只有当 0 ≤ i ≤ j < n 时,才会有 dp[i][j] > 0,否则 dp[i][j] = 0

i < j 时,计算 dp[i][j] 需要分别考虑 s[i]s[j] 相等不相等的情况:

  • 如果 s[i] = s[j],则首先得到 s 的下标范围 [i + 1, j − 1] 内的最长回文子序列,然后在该子序列的首尾分别添加 s[i]s[j],即可得到 s 的下标范围 [i,j] 内的最长回文子序列,因此 :
    dp [ i ] [ j ] = dp [ i + 1 ] [ j − 1 ] + 2 \textit{dp}[i][j] = \textit{dp}[i+1][j-1] + 2 dp[i][j]=dp[i+1][j1]+2

  • 如果 s[i] ≠ s[j],则 s[i]s[j] 不可能同时作为同一个回文子序列的首尾,因此:
    dp [ i ] [ j ] = max ⁡ ( dp [ i + 1 ] [ j ] , dp [ i ] [ j − 1 ] ) \textit{dp}[i][j] = \max(\textit{dp}[i+1][j], \textit{dp}[i][j-1]) dp[i][j]=max(dp[i+1][j],dp[i][j1])

由于状态转移方程都是从长度较短的子序列向长度较长的子序列转移,因此需要注意动态规划的循环顺序。

( 动态规划) 516. 最长回文子序列 ——【Leetcode每日一题】

最终得到 dp[0][n−1] 即为字符串 s 的最长回文子序列的长度。

⭐️ 空间优化

观察发现 dp[i][j] 只与dp[i][j-1] 以及第 i + 1行有关系,所以可以进行空间优化,只需要两个一维数组,分别为 firsec ,交替滚动即可,此时的状态转移方程为:

  • s[i] = s[j] :
    dp [ f i r ] [ j ] = dp [ s e c ] [ j − 1 ] + 2 \textit{dp}[fir][j] = \textit{dp}[sec][j-1] + 2 dp[fir][j]=dp[sec][j1]+2

  • 如果 s[i] ≠ s[j],则 s[i]s[j] 不可能同时作为同一个回文子序列的首尾,因此:
    dp [ f i r ] [ j ] = max ⁡ ( dp [ s e c ] [ j ] , dp [ f i r ] [ j − 1 ] ) \textit{dp}[fir][j] = \max(\textit{dp}[sec][j], \textit{dp}[fir][j-1]) dp[fir][j]=max(dp[sec][j],dp[fir][j1])

🍁代码:(Java、C++)

Java

public class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];
        for (int i = n - 1; i >= 0; i--) { // 从后往前遍历 保证情况不漏
            dp[i][i] = 1; // 初始化
            for (int j = i + 1; j < n; j++) {
                if (s.charAt(i) == s.charAt(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][n - 1];
    }
}

C++

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        for (int i = n - 1; i >= 0; i--) { // 从后往前遍历 保证情况不漏
            dp[i][i] = 1; // 初始化
            for (int j = i + 1; j < n; 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][n - 1];
    }
};

⭐️ 空间优化
Java

public class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[2][n];
        int fir = 0, sec = 1;
        for (int i = n - 1; i >= 0; i--) { // 从后往前遍历 保证情况不漏
            dp[fir][i] = 1; // 初始化
            for (int j = i + 1; j < n; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    dp[fir][j] = dp[sec][j - 1] + 2;
                } else {
                    dp[fir][j] = Math.max(dp[sec][j], dp[fir][j - 1]);
                }
            }
            int tmp = fir;
            fir = sec;
            sec = tmp;
        }
        return Math.max(dp[0][n - 1], dp[1][n - 1]);
    }
}

C++

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size();
        vector<vector<int>> dp(2, vector<int>(n));
        int fir = 0, sec = 1;
        for (int i = n - 1; i >= 0; i--) { // 从后往前遍历 保证情况不漏
            dp[fir][i] = 1; // 初始化
            for (int j = i + 1; j < n; j++) {
                if (s[i] == s[j]) {
                    dp[fir][j] = dp[sec][j - 1] + 2;
                } else {
                    dp[fir][j] = max(dp[sec][j], dp[fir][j - 1]);
                }
            }
            int tmp = fir;
            fir = sec;
            sec = tmp;
        }
        return max(dp[0][n - 1], dp[1][n - 1]);
    }
};
🚀 运行结果:

( 动态规划) 516. 最长回文子序列 ——【Leetcode每日一题】

🕔 复杂度分析:
  • 时间复杂度 O ( n 2 ) O(n^2) O(n2),其中 n 为字符串 s 的长度。
  • 空间复杂度 O ( n ) O(n) O(n),空间优化后只需两个一维数组;优化前的空间复杂度为 O ( n 2 ) O(n^2) O(n2)

题目来源:力扣。

放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!文章来源地址https://www.toymoban.com/news/detail-458037.html

注: 如有不足,欢迎指正!

到了这里,关于( 动态规划) 516. 最长回文子序列 ——【Leetcode每日一题】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • leetcode 516. 最长回文子序列(JAVA)题解

    题目链接 https://leetcode.cn/problems/longest-palindromic-subsequence/description/?utm_source=LCUSutm_medium=ip_redirectutm_campaign=transfer2china 目录 题目描述: 暴力递归: 动态规划: 给你一个字符串  s  ,找出其中最长的回文子序列,并返回该序列的长度。子序列定义为:不改变剩余字符顺序的情况

    2024年02月13日
    浏览(43)
  • (动态规划) 132. 分割回文串 II ——【Leetcode每日一题】

    难度:困难 给你一个字符串 s ,请你将 s 分割成一些子串,使每个子串都是回文。 返回符合要求的 最少分割次数 。 示例 1: 输入:s = “aab” 输出:1 解释:只需一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。 示例 2: 输入:s = “a” 输出:0 示例 3: 输入:

    2024年02月15日
    浏览(46)
  • 647.回文子串 516.最长回文子序列

    力扣题目链接(opens new window) 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。 示例 1: 输入:“abc” 输出:3 解释:三个回文子串: “a”, “b”, “c” 示例 2: 输入

    2024年01月19日
    浏览(44)
  • (动态规划) 剑指 Offer 48. 最长不含重复字符的子字符串 ——【Leetcode每日一题】

    难度:中等 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”,所

    2024年02月11日
    浏览(60)
  • Day 57|647. 回文子串| 516.最长回文子序列

    ● 647. 回文子串 ● 516.最长回文子序列 ● 动态规划总结篇 难

    2024年02月16日
    浏览(47)
  • 算法刷题|647.回文子串、516.最长回文子序列

    题目:给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。 d

    2024年02月17日
    浏览(50)
  • 【五一创作】( 字符串) 409. 最长回文串 ——【Leetcode每日一题】

    难度:简单 给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串 。 在构造过程中,请注意 区分大小写 。比如 \\\"Aa\\\" 不能当做一个回文字符串。 示例 1: 输入:s = “abccccdd” 输出:7 解释: 我们可以构造的最长的回文串是\\\"dccaccd\\\", 它的长度是

    2024年02月01日
    浏览(56)
  • 动态规划-最长的回文序列

    该题是lintcode上 667 · 最长的回文序列,该题的解题思路亦是参考了九章侯老师的解题思路给出。 给一字符串 s, 找出在 s 中的最长回文子序列的长度. 你可以假设 s 的最大长度为 1000. 输入: “bbbab” 输出: 4 解释: 一个可能的最长回文序列为 “bbbb” 输入: “bbbbb” 输出:

    2024年02月09日
    浏览(47)
  • 代码随想录 Day - 59|#647 回文字串|#516 最长回文子序列

    ● 647. 回文字串 ● 516. 最长回文子序列 给你一个字符串 s ,请你统计并返回这个字符串中回文子串的数目。 回文字符串是正着读和倒过来读一样的字符串。 子字符串是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成

    2024年02月07日
    浏览(42)
  • 动态规划学习——最长回文子序列,让字符串变成回文串的最小插入次数

    1.题目 给你一个字符串  s  ,找出其中最长的回文子序列,并返回该序列的长度。 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。 示例 1: 示例 2: 提示: 1 = s.length = 1000 s  仅由小写英文字母组成 2.题目接口  3.解题思路

    2024年02月04日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包