【算法 - 动态规划】最长公共子序列问题

在上两篇文章中,我们将 暴力递归 逐步修改成为 动态规划 ,并介绍了有严格 dp表依赖 和无表依赖结构的解题方法。其中,前篇文章中的纸牌博弈问题属于 [L , R]上范围尝试模型。该模型给定一个范围,在该范围上进行尝试,套路就是 思考 [L ,R] 两端该如何取舍。

本篇文章我们学习一个新的模型: 样本对应模型,该模型的套路就是 以结尾位置为出发点,思考两个样本的结尾都会产生哪些可能性

力扣1143:最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

输入: text1 = “abcde”, text2 = “ace”

*输出:*3

*解释:*最长公共子序列是 “ace” ,它的长度为 3 。

示例 2:

*输入:*text1 = “abc”, text2 = “def”

*输出:*0

*解释:*两个字符串没有公共子序列,返回 0 。

首先我们依然采用最朴素的 暴力递归 来思考这道题目。

递归的准备

定义递归函数的功能: 返回 str1 中 [0...i] ,str2 中 [0...j] 范围上两个字符串的最长公共子序列。

思考递归需要的参数: str1, str2 两个字符串,分别要比较的范围 i, j。

明确递归的边界条件: 当两个字符串长度均为 1 时:若两个字符相同返回 1 ,不同返回 0 。

思路

这道题就是典型的 样本对应模型 ,因此,递归就可以按照 两个样本的结尾都会产生哪些可能性 的思路来划分情况:

  • 公共子序列 既不以 str1 结尾,也不以 str2 结尾;
  • 公共子序列 str1 结尾,不以 str2 结尾;
  • 公共子序列 不以 str1 结尾, str2 结尾;
  • 公共子序列 既以 str1 结尾,也以 str2 结尾。

因为要求 最长 子序列,因此要返回这四种情况当中的最大值。

代码

public static int longestCommonSubsequence(String s1, String s2) {
    if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
        return 0;
    }
    char[] str1 = s1.toCharArray();
    char[] str2 = s2.toCharArray();
    return process(str1, str2, str1.length - 1, str2.length - 1);
}

public static int process(char[] str1, char[] str2, int i, int j) {
    if (i == 0 && j == 0) {
        return str1[i] == str2[j] ? 1 : 0;
    } else if (i == 0) {
        return str1[i] == str2[j] ? 1 : process(str1, str2, i, j - 1);
    } else if (j == 0) {
        return str1[i] == str2[j] ? 1 : process(str1, str2, i - 1, j);
    } else {
        int p1 = process(str1, str2, i - 1, j - 1);
        int p2 = process(str1, str2, i, j - 1);
        int p3 = process(str1, str2, i - 1, j);
        int p4 = str1[i] == str2[j] ? 1 + process(str1, str2, i - 1, j - 1) : 0;
        return Math.max(Math.max(p1, p2), Math.max(p3, p4));
    }
}

代码解释

因为递归调用中使用到了 i-1 , j-1,因此需要做边界处理。例如:当str1 中只剩下一个字符时,若与 str2 最后一个字符相等即找到了此时最长子序列,否则排除掉 str2 的最后一个字符继续递归寻找。


写出该暴力版的递归之后发现,最终要求的是最大值,因此其实 p1 的情况是一定不会比 p2 ,p3 的情况返回值要大,所以可以减少一次递归的调用,做个小小的优化。

动态规划版

public static int longestCommonSubsequence(String s1, String s2) {
    if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
        return 0;
    }
    char[] str1 = s1.toCharArray();
    char[] str2 = s2.toCharArray();
    int N = str1.length;
    int M = str2.length;
    int[][] dp = new int[N][M];
    // 处理 str1 和 str2 均剩下一个字符的情况
    dp[0][0] = 1;
    // 处理 str1 剩下一个字符的情况 
    for (int j = 1; j < M; j++) {
        dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1];
    }
    // 处理 str2 剩下一个字符的情况 
    for (int i = 1; i < N; i++) {
        dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
    }
    // str1 str2 均有多个字符的情况
    for (int i = 1; i < N; i++) {
        for (int j = 1; j < M; j++) {
            int p1 = dp[i][j - 1];
            int p2 = dp[i - 1][j];
            int p3 = str1[i] == str2[j] ? 1 + dp[i - 1][j - 1] : 0;
            dp[i][j] = Math.max(Math.max(p1, p2), p3);
        }
    }
    return dp[N - 1][M - 1];
}

代码解释

根据递归函数修改出这套动态规划版代码就非常容易了。

以 str1 = “abcde”, str2 = “ace” 为例

可变的参数有两个:str1str2 判断长度范围的 ij。因此,需要设置一个二维的 dp 表数组,由于 i, j 的取值范围从 0 开始到字符串长度减一,因此数组大小设置为 dp[N][M]

递归代码 i==0 && j==0 可知,初始只有 dp[0][0] 的值为 1 。

i == 0j == 0时,只依赖左侧或上侧的数值。

当 str1 和 str2 均有多个字符时,会依赖 左,上,左上 三个地方的 最大值


由递归调用函数 process(str1, str2, str1.length - 1, str2.length - 1) 可知,最终要求的是 dp[N - 1][M - 1] 的值 3

总结

本篇文章我们学习了一个新的分析模型 —— 样本对应模型 。该模型的套路就是: 以结尾位置为出发点,思考两个样本的结尾都会产生哪些可能性

下篇文章我们继续学习类似的题型,但分析模型可以完全不一样哦,敬请期待!

~ 点赞 ~ 关注 ~ 不迷路 ~!!!

------------- 往期回顾 -------------
【算法 - 动态规划】力扣 691. 贴纸拼词
【算法 - 动态规划】原来写出动态规划如此简单!
【算法 - 动态规划】从零开始学动态规划!(总纲)
【堆 - 专题】“加强堆” 解决 TopK 问题!
AC 此题,链表无敌!!!

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

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

相关文章

word文件中的图片压缩怎么操作?这几招教你轻松压缩

word文件中的图片压缩怎么操作&#xff1f;在日常办公中&#xff0c;我们经常需要在Word文档中插入图片来丰富内容。但有时候&#xff0c;插入的图片过大&#xff0c;不仅会增加文档的打开速度&#xff0c;还可能影响打印效果。那么&#xff0c;如何在保持图片质量的同时&#…

Android 面试问题 2024 版(其一)

Android 面试问题 2024 版&#xff08;其一&#xff09; 一、Java 和 Kotlin二、安卓组件三、用户界面 (UI) 开发四、安卓应用架构五、网络和数据持久性 一、Java 和 Kotlin Java 中的抽象类和接口有什么区别&#xff1f; 答&#xff1a;抽象类是不能实例化的类&#xff0c;它…

番茄工作法规则

番茄工作法规则: 一个番茄钟共30分钟&#xff0c;包括25分钟的工作时间和5分钟的休息时间。每完成四个番茄钟&#xff0c;就进行一次较长时间的休息&#xff0c;大约15-30分钟。一个番茄钟是不可分割的&#xff0c;一旦开启就必须坚持到底&#xff0c;如果打断&#xff0c;就视…

万界星空科技MES系统,实现数字化智能工厂

万界星空科技帮助制造型企业解决生产过程中遇到的生产过程不透明&#xff0c;防错成本高&#xff0c;追溯困难&#xff0c;品质不可控&#xff0c;人工效率低下&#xff0c;库存积压&#xff0c;交期延误等问题&#xff0c;从而达到“降本增效”的目标。打通各个信息孤岛&#…

英伟达推出ConsiStory免训练文生图模型;Sora物理悖谬的几何解释;Groq推出全球最快大模型

&#x1f989; AI新闻 &#x1f680; 英伟达推出ConsiStory免训练文生图模型 摘要&#xff1a;ConsiStory是一种免训练的一致性连贯文生成图模型&#xff0c;由英伟达和特拉维夫大学的研究人员开发。它解决了文生成图模型在生成内容一致性方面的两个主要问题。首先&#xff0…

顺序表漫谈

目录 ​编辑 1.线性表 2.顺序表 2.1概念及结构 2.2接口实现 1.顺序表的动态存储 2.顺序表初始化 3.顺序表销毁 4.顺序表增容 5.顺序表头插 6.顺序表尾插 7.顺序表头删 8.顺序表尾删 9.顺序表打印 10.顺序表在任意下标位置插入数据 11.顺序表删除任意下标位置的值…

VIO第2讲:IMU标定实验

VIO第2讲&#xff1a;IMU标定实验 文章目录 VIO第2讲&#xff1a;IMU标定实验5 IMU标定实验5.1 仿真数据产生5.1.1 c代码分析5.1.2 生成ros包数据 5.2 Allan方差实验&#xff08;港科大imu_utils&#xff09;5.2.1 安装5.2.2 运行 5.3 Allan方差实验&#xff08;matlab代码kali…

深度学习基础——GAN生成对抗网络

生成对抗网络(GAN)的简介 生成对抗网络GAN(Generative adversarial networks)是Goodfellow等在2014年提出的一种生成式模型。GAN在结构上受博弈论中的二元零和博弈(即二元的利益之和为零&#xff0c;一方的所得正是另一方的所失)的启发&#xff0c;系统由一个生成器和一个判别器…

pc微信逆向最新3.9.8.25版本

朋友让我开发一个关于微信的计数、统计、自动回复功能的机器人&#xff0c;主要是用在win10上面。 先看看结果&#xff01; 之前写过手机端的逆向&#xff0c;PC端逆向很长时间没写了&#xff0c;所以就在网上找了找。基本都是基于3.6&#xff0c;3.7&#xff0c;3.8版本的&a…

python读取txt文档数据并断言value值的大小

本文主要介绍&#xff1a;将接口返回的字典值{"x1":1,"x2":2....}手动存到txt&#xff0c;然后写代码断言每个value值是否都满足某个区间。运用到&#xff1a; 1、读取txt文件中的数据 2、pytest写用例格式 3、pytest.assume断言方式&#xff08;出现报错A…

C++力扣题目139--单词拆分 198--打家劫舍 213--打家劫舍II 337打家劫舍III

139.单词拆分 力扣题目链接(opens new window) 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 …

【IEEE出版会议征稿】第七届计算机信息科学与应用技术国际学术会议(CISAT 2024)

【IEEE出版】第七届计算机信息科学与应用技术国际学术会议&#xff08;CISAT 2024&#xff09; 2024 7th International Conference on Computer Information Science and Application Technology 第七届计算机信息科学与应用技术国际学术会议&#xff08;CISAT 2024&#x…

低代码:更高效、简单的方式开发出专业级的项目

你是否为编程世界的各种挑战感到头痛&#xff1f;想要以更高效、简单的方式开发出专业级的项目&#xff1f; JNPF低代码工具正是你苦心寻找的产品&#xff01;它是一款专为稍微懂一点点编程思想的入门级人员设计的神奇工具&#xff0c;集成了丰富的功能和组件&#xff0c;让你轻…

[NOIP2016 普及组] 魔法阵(枚举的典型例题,值得一看)

在透视这道题之前&#xff0c;先用一道小题来练练手 密码锁&#xff08;这道题是我根据魔法阵改的&#xff09; Description 叮当在探索迷宫时被一扇大门挡住了去路&#xff0c;门上刻画了很多乱七八糟的数字&#xff0c;门被锁上了&#xff0c;无法打开&#xff0c;但是门上…

WebGIS开发常用的JS库:VUE/React/Angular对比

Angular: 作用&#xff1a; Angular是一个完整的基于TypeScript的Web应用开发框架&#xff0c;主要用于构建单页Web应用&#xff08;SPA&#xff09;。它适用于大型和复杂的项目&#xff0c;具有强大的组件集合和丰富的文档。 架构&#xff1a; Angular采用组件化的方式&am…

【DC-DC】世微AP5192 LED恒流IC 摩托电动车货车 12-80V 1.5A 有极输入 电源驱动芯片

产品描述 AP5192是一款PWM工作模式,效率高、简单、内置功率MOS管&#xff0c;适用于4.5-100V输入的高精度降压LED恒流驱动芯片。电流1.5A。AP5192可实现线性调光和PWM调光&#xff0c;线性调光脚有效电压范围0.55-2.6V.AP5192 工作频率可以通过RT 外部电阻编程来设定&#xff0…

[经验] 动车盒饭价格2022 #其他#职场发展

动车盒饭价格2022 1、动车盒饭 近年来&#xff0c;随着中国高速铁路的发展&#xff0c;动车盒饭也成为了不可忽视的一份美食。它不仅解决了旅途中的饮食需求&#xff0c;还体现了中国美食文化的多样性和可口。 动车盒饭是一种便捷且美味的餐食&#xff0c;在火车上也不失为一…

胶原蛋白市场研究:预计2029年将达到27亿美元

胶原蛋白是一种白色、无支链的纤维状蛋白&#xff0c;是细胞外间质蛋白质的主要成分&#xff0c;占人体总蛋白质的25%到30%。 按胶原蛋白来源划分&#xff0c;可分为天然胶原蛋白和人工合成的胶原蛋白&#xff0c;后者以重组类人胶原蛋白为主&#xff0c;而重组类人胶原蛋白又可…

失败了,又继续失败了

这是一个普通的老人在小县城坚持写作的故事。与很多人的老年生活不同&#xff0c;78岁的舒绍平每天过着规律的写作生活&#xff0c;不做家务的时候&#xff0c;他便坐在书房&#xff0c;打开笔记本电脑&#xff0c;时断时续地敲字写作。 年轻时&#xff0c;他当过老师&#xf…

五种多目标优化算法(MOJS、MOGWO、NSWOA、MOPSO、NSGA2)性能对比,包含6种评价指标,9个测试函数(提供MATLAB代码)

一、5种多目标优化算法简介 1.1MOJS 1.2MOGWO 1.3NSWOA 1.4MOPSO 1.5NSGA2 二、5种多目标优化算法性能对比 为了测试5种算法的性能将其求解9个多目标测试函数&#xff08;zdt1、zdt2 、zdt3、 zdt4、 zdt6 、Schaffer、 Kursawe 、Viennet2、 Viennet3&#xff09;&#xff0…