LCSS—最长回文子序列

思路分析

        关于”回文串“的问题,是面试中常见的,本文提升难度,讲一讲”最长回文子序列“问题,题目很好理解:

        输入一个字符串 s,请找出 s 中的最长回文子序列长度。

        比如输入 s="aecda",算法返回3,因为最长回文子序列是 "aca",长度是3。

        这个问题对 dp 数组的定义是:在子串 s[i...j] 中,最长回文子序列的长度为 dp[i][j]。一定要记住这个定义才能理解算法。

        为什么这个问题要这样定义二维的 dp 数组呢?找状态转移需要归纳思维,说白了就是如何从已知的结果推出未知的部分,这样定义容易归纳,容易发现状态转移关系。

        具体来说,如果想求 dp[i][j],假设知道了子问题 dp[i+1][j-1] 的结果( s[i+1...j-1] 中最长回文子序列的长度),是否能想办法算出 dp[i][j] 的值( s[i...j] 中最长回文子序列的长度)呢?

        可以!这取决于 s[i] 和 s[j] 的字符:

        如果它俩相等,那么它俩加上 s[i+1...j-1] 中的最长回文子序列就是 s[i...j] 的最长回文子序列:

        如果它俩不相等,说明它俩不可能同时出现在 s[i...j] 的最长回文子序列中,那么把它俩分别加入 s[i+1...j-1]中,看看哪个子串产生的回文子序列更长即可:

        以上情况写成代码就是这样:

        if (s[i] == s[j])

                //  它俩一定在最长回文子序列中

                dp[i][j] = dp[i+1][j-1] + 2

        else

                // s[i+1...j] 和 s[i...j-1] 谁的回文子序列更长?

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

        至此,状态转移方程就写出来了,根据 dp 数组的定义,我们要求的就是 dp[0][n-1],也就是整个 s 的最长回文子序列的长度。

代码实现

        首先明确基本情况,如果只有一个字符,显然最长回文子序列长度是1,也就是 dp[i][j] = 1 (i == j)。因为 i 肯定小于或等于 j,所以对于那些 i > j 的位置,根本不存在什么子序列,应该初始化为0。另外,看看刚才写的状态转移方程,想求 dp[i][j] 需要知道 dp[i+1][j-1]、dp[i+1][j] 和 dp[i][j-1]这三个位置;再看看我们确定的基本情况,填入 dp 数组之后是这样的:

        为了保证每次计算 dp[i][j],左下右方向的位置已经被计算出来,只能斜着遍历或者反着遍历。这里选择反着遍历,代码如下:

package DynamicProgramming;

// leetcode 516 最长回文子序列
public class LCSS {

    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        // 创建 dp 数组
        int[][] dp = new int[n][n];
        // base case
        for (int i = 0; i < n; i++) {
            dp[i][i] = 1;
        }
        // 反向遍历保证正确的状态转移
        for (int i = n - 2; i >= 0; i--) {
            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]);
                }
            }
        }
        // 整个 s 的最长回文子序列长度
        return dp[0][n - 1];
    }

    public static void main(String[] args) {
        LCSS lcss = new LCSS();
        int len = lcss.longestPalindromeSubseq("aecda");
        System.out.println(len);
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/875455.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

考题:将数组的元素内容反转

考题&#xff1a;把数组的元素内容反转&#xff0c;int[ ] arr {11,22,33,44,55};变成int[ ] arr{55,44,33,22,11} 小伙伴们可以自己先思考再看解析&#xff1a; 方法1&#xff1a; 思想&#xff1a;两杯水交换的思想&#xff08;有一杯装满水的杯子a和一杯装满水的杯子b,想想…

STM32双轮平衡小车(基于STM32F103C8T6HAL库)

STM32双轮平衡小车参考教程 这个项目是跟做以上UP的STM32双轮平衡小车&#xff0c;主要是为了学习电机驱动和PID控制。这篇我就不提供源码了&#xff0c;我也是跟学的&#xff0c;原作者也提供了源码&#xff0c;我记录一下自己的理解。 1 PID原理 1.1 PID简介 1.2 PID演示 …

基于SpringBoot+Vue+MySQL的笔记记录分享网站

系统展示 用户前台界面 管理员后台界面 系统背景 在当今数字化时代&#xff0c;笔记记录与分享已成为学习、工作与生活中不可或缺的一部分。为了满足用户高效整理思绪、便捷分享知识的需求&#xff0c;我们设计了一款基于SpringBoot后端框架、Vue前端框架及MySQL数据库的笔记记…

存储课程学习笔记1_访问scsi磁盘读写测试(struct sg_io_hdr,ioctl,mmap)

创建虚拟机时&#xff0c;可以选择SCSI,STAT,NVME不同类型的磁盘。 0&#xff1a;总结 》了解内核提供的访问scsi的结构和方法 &#xff08;主要是sg_io_hdr_t 结构体和ioctl函数&#xff09;。 》需要读scsi协议文档&#xff0c;了解相关指令&#xff0c;只演示了16字节固定…

Leetcode第414周赛第二题:3281. 范围内整数的最大得分

一&#xff1a;题目&#xff1a; 给你一个整数数组 start 和一个整数 d&#xff0c;代表 n 个区间 [start[i], start[i] d]。 你需要选择 n 个整数&#xff0c;其中第 i 个整数必须属于第 i 个区间。所选整数的 得分 定义为所选整数两两之间的 最小 绝对差。 返回所选整数的…

利他决策的神经机制:脑电功能连接网络分析

摘要 利他主义是一种复杂的亲社会行为&#xff0c;具有多样性的动机和显著的个体差异。研究利他主义的神经机制对于识别行为中的亲社会和反社会倾向的客观标志至关重要。本研究旨在通过网络方法分析基于EEG的功能连接模式来深入探讨利他主义的机制。为了实验性地引发利他决策情…

eclipse配置maven

eclipse配置maven 启动 Eclipse&#xff0c;转到 Window > Preferences 在左侧导航栏中&#xff0c;展开 Maven 节点。 在 User Settings 下&#xff0c;单击 Add。 浏览到 Maven 安装目录中 conf/settings.xml 文件。 在 Global Settings 下&#xff0c;单击 Add。 浏览到…

动态规划算法---04.斐波那契数列模型_解码方法_C++

题目链接&#xff1a;91. 解码方法 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/decode-ways/description/ 一、题目解析 题目&#xff1a; 题目大意&#xff1a;从题目中我们可以知道&#xff0c;解码就是在字符串s中由‘1’到‘26’的字符可以转化…

架构模式:MVC

引言 MVC&#xff0c;即 Model&#xff08;模型&#xff09;-View&#xff08;视图&#xff09;-Controller&#xff08;控制器&#xff09;&#xff0c;是广泛应用于交互式系统中的典型架构模式&#xff0c;尤其在 GUI 和 Web 应用中。 MVC 的概念源自 GOF&#xff08;Gang …

Web安全之GroovyShell讲解:错误与正确示范,安全问题与解决方案

第一章、引言 Groovy 是一门基于 Java 虚拟机&#xff08;JVM&#xff09;的动态语言&#xff0c;而 GroovyShell 是 Groovy 提供的一个灵活强大的脚本执行工具。通过 GroovyShell&#xff0c;开发者可以在运行时动态执行 Groovy 脚本&#xff0c;它的灵活性非常适合那些需要动…

多层建筑能源参数化模型和城市冠层模型的区别

多层建筑能源参数化&#xff08;Multi-layer Building Energy Parameterization, BEP&#xff09;模型和城市冠层模型&#xff08;Urban Canopy Model, UCM&#xff09;都是用于模拟城市环境中能量交换和微气候的数值模型&#xff0c;但它们的侧重点和应用场景有所不同。以下是…

MongoDB事务机制

事务机制 1.事务概念 在对数据的操作的过程中&#xff0c;涉及到一连串的操作&#xff0c;这些操作如果失败&#xff0c;会导致我们的数据部分变化了&#xff0c;部分没变化。这个过程就好比如你去吃早餐&#xff0c;你点完餐了&#xff0c;并且吃完早餐了&#xff0c;没付钱你…

【文件包含】——日志文件注入

改变的确很难&#xff0c;但结果值得冒险 本文主要根据做题内容的总结&#xff0c;如有错误之处&#xff0c;还请各位师傅指正 一.伪协议的失效 当我们做到关于文件包含的题目时&#xff0c;常用思路其实就是使用伪协议&#xff08;php:filter,data,inpput等等&#xff09;执行…

职业技能大赛背景下的移动互联网应用软件开发(Android)实训室建设方案

一、建设背景 随着科技的持续进步&#xff0c;移动设备已成为人们日常生活中不可或缺的一部分。据相关数据&#xff0c;移动互联网的使用率在近年来显著上升。在这样的背景下&#xff0c;移动互联技术不仅推动了科技的发展&#xff0c;也渗透到了智能家居、车联网、工业自动化…

TESSY创建需要手写桩的测试用例

如果需要让桩函数有额外的功能&#xff0c;如&#xff1a;传参检测、局部数据处理、多传参检测、函数实现变更等&#xff0c;可以进行手写桩。 我们以tessy5.1 IDE为例&#xff0c;给大家展示编写一个需要手写桩的测试用例过程。 1、前期的准备工作 可以参考以下文章&#xff1…

Qt常用控件——QTextEdit

文章目录 QTextEdit核心属性和信号同步显示示例信号示例 QTextEdit核心属性和信号 QTextEdit表示多行输入框&#xff0c;是一个富文本和markdown编辑器&#xff0c;并且能在内存超出编辑框范围时自动提供滚动条。 QPlainTexEdit是纯文本&#xff0c;QTextEdit不仅表示纯文本&a…

记得忘记密码情况下如何退出苹果Apple ID

在日常使用苹果手机时&#xff0c;我们可能会遇到需要退出Apple ID的情况&#xff0c;比如更换手机、不再使用某些服务或出于安全考虑等。下面&#xff0c;我们就来详细介绍一下苹果手机如何退出Apple ID。 情况一&#xff1a;记得Apple ID密码 若是记得Apple ID密码&#xff…

Tomcat服务详解

一、部署Tomcat服务器 JDK安装官方网址&#xff1a;https://www.oracle.com/cn/java Tomcat安装官方网址&#xff1a;Apache Tomcat - Welcome! 安装JDK 1.获取安装包 wget https://download.oracle.com/otn/java/jdk/8u411-b09/43d62d619be4e416215729597d70b8ac/jdk-8u41…

透明任务栏怎么设置?Windows电脑任务栏透明效果(详尽指南)

电脑任务栏可以自定义调整透明度&#xff0c;在Windows10和Windows11系统中&#xff0c;任务栏透明是默认不透明的。如果想要设置任务栏透明度&#xff0c;那么推荐以下方法实现&#xff0c;简单三个步骤即可实现&#xff0c;一起来看看吧&#xff01; 第一步、选择合适的任务栏…

基于鸿蒙API10的RTSP播放器(五:拖动底部视频滑轨实现跳转)

拖动前播放位置&#xff1a; 拖动后播放位置&#xff1a; 在Slider组件中&#xff0c;添加onChange方法进行监听&#xff0c;当视频轨道拖放结束时&#xff0c;触发this.seekTo()函数&#xff0c;其中seekTo函数需要传递一个视频已播放时长作为参数 Slider({ value: this.p…