首页 > 其他分享 >最长回文子序列

最长回文子序列

时间:2024-11-15 15:49:24浏览次数:3  
标签:string int max length 序列 最长 dp 回文

*************

C++

题目来源:516. 最长回文子序列 - 力扣(LeetCode)

*************

看一下题目

这个让我想到前几天做过的最长回文子串,那个简单的中心拓展法我不会,头铁做成了dp数组,有点忘了,重新做一下。

最长回文子串的题目是:给定一个字符串 s ,找出其最长的回文子串。简单地找到两个字母组成的子串就是比较 bool (dp[i], dp[i + 1]),

for (int len = 3; len <= n; len++) { // assume only 3 elements in the string
            for (int i = 0; i < n - len + 1; i++) { // 
                int j = i + len - 1; // assume the last element
                if (s[i] == s[j] && dp[i + 1][j - 1]) {
                    dp[i][j] = true;
                    longest = s.substr(i, len);
                }
            }
        }

回到题目,那就可以按照这个逻辑,在原有的基础上开始优化。这个像模糊拼音输入法的逻辑。就好像我想打的这个,实际上, jiuhaoxing 可能是 jiuhaoxiang 或则 jiuhaoxig,都能打出就好像。

到这里,就大概知道了这个题目在生活中的应用了。

起手也是正常的获得字符串 s 的长度,初始化一个dp数组用于存储新的寻找下来的序列串。

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size(); // get the length of the string
        vector<vector<int>> dp(n, vector<int>(n, 0)); // initialise the array into elements zero
};

接下来我会用上我的老朋友,矩阵,来帮我理解接下来的代码顺序。我喜欢在在工作的时候碎碎念,这样会帮助我理清思路。假如我是计算机,我获得了一组字符串,

s = "apple"

首先 n = 5;这一步很简单,一共五个字母,熟悉十以内加减法的人都知道。

初始化矩阵,并且矩阵中所有的元素都为 0;

01234
apple
0a00000
1p00000
2p00000
3l00000
4e00000

定义 dp[i][i] = 1,这个很简单,因为只包含1个字母的字符串肯定是回文。

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size(); // get the length of the string
        vector<vector<int>> dp(n, vector<int>(n, 0)); // initialise the array into elements zero

        for (int i = 0; i < n; i++){
            dp[i][i] = 1; // ez to understand that one letter is always true
        }
};

01234
apple
0a10000
1p01000
2p00100
3l00010
4e00001

第二步就是,找到2个字母的回文串。这个的判断很简单,就是s[i] == s[i + 1]。

  • 检查 s[0] 和 s[1],它们是 'a' 和 'p',不相等,所以 dp[0][1] = max(dp[1][1], dp[0][0]) = max(1, 1) = 1
  • 检查 s[1] 和 s[2],它们是 'p' 和 'p',相等,所以 dp[1][2] = max(dp[2][2], dp[1][1]) = max(3, 1) = 3
  • 检查 s[2] 和 s[3],它们是 'p' 和 'l',不相等,所以 dp[2][3] = max(dp[3][3], dp[2][2]) = max(1, 3) = 3
  • 检查 s[3] 和 s[4],它们是 'l' 和 'e',不相等,所以 dp[3][4] = max(dp[4][4], dp[3][3]) = max(1, 3) = 3

这里得重申一下 dp[s][m] 的概念,这里是以字符串中 s 为起点, m 为终点的字符串中,可以组成回文的字符串长度。

01234
apple
0a11000
1p13300
2p03330
3l00333
4e00031

这里是比较难理解的,好在我还会一个东西,就是举例子,穷举美学,我的apple。

既然 dp[s][m] 表示 s()中,第s位到第m位,这里规定一下m < s,顺便普及一个冷知识, s的全拼是 sadism,并且m 的全拼是 masochism,简单地学习两个英文单词。

sdp[s + 1][m - 1]m

假如,已知 dp[s + 1][m - 1] 是回文子串,注意这里是串,串不可以增加或者减少元素,

那么我就要知道dp[s][m] = dp[s + 1][m - 1] + 2,因为是长度,首尾各加一个字母。

还是以 s = "apple" 举例,我看得出来 这个有一个回文是 ss

sapple
i01234

如果 length = 2,也就是说dp[1][2] = 2,那么,我就要看一下s[0] != s[3],这里显然 a != l的值是false,也就是说dp[0][3] = 2,穷举美学来了,既然dp[0][3] = 2,那我观察一下s[0] != s[2],这里等价于dp[0][2],显然s[0] != s[2]是false,向左穷举美学不美,向右试一试,s[1] != s[3]的值也是false,因为p ≠ l。

这里定义一个指针i,从以一个元素开始遍历, j =  i + length - 1,目的是保证所有的串都能烤到。以 length = 2 开始,

i = 0; length = 2; j = 1; s = {a, p}; 不是回文;接着问;

i = 1; length = 2; j = 2; s = {p, p}; 是回文;进入循环, if {s[1] == s[2]},那就 dp[1][2] = dp[2][1] + 2,这个显然是不对的, 因为设置的i < j,所以要加一个判断条件,新赋值的 {i + 1 <= j - 1 ?},这句话的意思代表  {i + 1 <= j - 1是对的吗?}  显然这里不是,因此要进入判断了,dp[1][2] = max(dp[2][2], dp[1][1]);继续循环;

i = 1; length = 3; j = 3; s = {p, p, l}; s[1] ≠ s[3],dp[1][3] = max(dp[1 + 1][3], dp[1][3 - 1])

i = 1; length = 4; j = 4; s = {p, p, l, e}; s[1] ≠ s[4],dp[1][4] = max(dp[1 + 1][4], dp[1][4 - 1])

总结:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])

因此可以把最重要的代码写出来了:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size(); // get the length of the string
        vector<vector<int>> dp(n, vector<int>(n, 0)); // initialise the array into elements zero

        for (int i = 0; i < n; i++){
            dp[i][i] = 1; // ez to understand that one letter is always true
        }

        // caculate the length more than 2
        for (int len = 2; len <= n; ++len) { // out-cicle is the length of the new string
            for (int i = 0; i <= n - len; ++i) { // in-cicle start from the different place
                int j = i + len - 1; // define the end of the string
                if (s[i] == s[j]) { // in new srtring, stare == end, which has the possibility, so need check
                    dp[i][j] = (i + 1 <= j - 1 ? dp[i + 1][j - 1] : 0) + 2;
                } else {
                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        
        // dp[0][n-1] return
        return dp[0][n - 1];
    }
};

这里举例子的暴力美学就在于,所有的情况都被考虑到了。

length = 1 ~ n; 

这里一个很重要的想法是,在计算dp[i][j]的时候,先判断s[i] = s[j] ?,如果是,那就是一个崭新的回文子串,直接 dp[i][j] = dp[i + 1][j - 1] + 2, 那如果不是,那就是掐头或者祛尾的那个较大的值。

最后的最后,周五了,又活了一周,真的很棒。

周末快乐。

标签:string,int,max,length,序列,最长,dp,回文
From: https://blog.csdn.net/ElseWhereR/article/details/143785381

相关文章

  • java 反序列化 cc5复现
    复现环境:common-collections版本<=3.2.1,java版本随意.cc5则是cc6的一个变形,换了一个出口.直接从有变化的位置开看.TiedMapEntrypublicclassTiedMapEntryimplementsMap.Entry,KeyValue,Serializable{privatestaticfinallongserialVersionUID=-84538693613......
  • LCR 016. 无重复字符的最长子串(中等)(主站3)
    https://leetcode.cn/problems/wtcaE1/https://leetcode.cn/problems/longest-substring-without-repeating-characters/难度:☆☆☆题目:给定一个字符串s,请你找出其中不含有重复字符的最长连续子字符串的长度。示例:输入:s=“abcabcbb”输出:3输入:s=“b......
  • P2501 [HAOI2006] 数字序列
    [题目链接]([P2501HAOI2006]数字序列-洛谷|计算机科学教育新生态)首先是第一问,直接求不好求,我们们考虑求不用更改的数量,发现有这个性质,如果,a[i]-a[j]<abs(j-i)两个数的差值能满足他们之间有足够多数的情况,例如1453,取1和3,那么就有2<3,中间的4和5怎么改也不......
  • 代码随想录算法训练营day46| 647. 回文子串 516.最长回文子序列
    学习资料:https://programmercarl.com/0647.回文子串.html#算法公开课动态规划最后一部分:回文字符串子串是从原字符串中连续截取的;子序列可以是从原字符串中不连续提取出元素构成的学习记录:647.回文子串(难构造dp数组,dp数组是从原字符串截取[i,j]范围的片段是否是回文字符串,布尔......
  • java 反序列化 cc3 复现
    版本要求:jdk版本<=8u65,common-collections版本<=3.2.1在很多时候,Runtime会被黑名单禁用.在这些情况下,我们需要去构造自定义的类加载器来加载自定义的字节码.类加载机制双亲委派这里直接粘别人的了.实现一个自定义类加载器需要继承ClassLoader,同时覆盖findClass方法......
  • java 反序列化 cc4 复现
    复现环境:jdk<=8u65,commonsCollections=4.0CommonsCollections4.x版本移除了InvokerTransformer类不再继承Serializable,导致无法序列化.但是提供了TransformingComparator为CommonsCollections3.x所没有的,又带来了新的反序列化危险.cc4的执行命令部分依然沿用cc3的TemplatesI......
  • 数据结构 ——— 利用前序序列重建链式二叉树
    目录题目要求链式二叉树示意图​编辑代码实现 题目要求读入用户输入的一串前序遍历的字符串,根据此字符串建立一个链式二叉树例如前序遍历的字符串为:ABC##DE#G##F###;其中"#"表示空树链式二叉树示意图以此图的链式二叉树为例子那么此链式二叉树前序遍历转换为字符......
  • 自定义序列化
    #ifndefAI_PACS_JSONTOSTRUCT_H#defineAI_PACS_JSONTOSTRUCT_H#include<iostream>#include<string>#include<unordered_map>#include<variant>#include<vector>#include<nlohmann/json.hpp>#include<stdexcept>......
  • MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测
    目录项目背景介绍...1项目目标与意义...1项目挑战...1项目特点与创新...1项目应用领域...2项目效果预测图程序设计...2项目模型架构...2项目模型描述...2项目模型算法流程图...4项目结构设计...5项目部署与应用...5项目扩展...5项目应该注意事项...5......
  • 代码随想录算法训练营day45| 115.不同的子序列 583. 两个字符串的删除操作 72.
    学习资料:https://programmercarl.com/0115.不同的子序列.html#算法公开课动态规划系列之编辑距离问题学习记录:115.不同的子序列(当遇到相同字母时,可以选择也可以不选;刚开始没看懂;dp[i][j]是对应i-1结尾和j-1结尾,这样的目的是方便第一行和第一列初始化)点击查看代码classSolut......