数据结构与算法之最长公共子序列动态规划

news2024/11/27 0:35:46
目录:
一.题目及其示例
二.动态规划的基本思想
三.思路
动态规划五部曲
1.确定dp数组(dp table)以及下标的含义
2.确定递推公式
3.dp数组如何初始化
4.确定遍历顺序
5.举例推导dp数组

一.题目及其示例

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

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

例如:"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

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

若这两个字符串没有公共子序列,则返回 0。

示例 1:输入:text1 = "abcde", text2 = "ace"

输出:3

解释:最长公共子序列是 "ace",它的长度为 3;

示例 2: 输入:text1 = "abc", text2 = "abc"

输出:3

解释:最长公共子序列是 "abc",它的长度为 3;

示例 3: 输入:text1 = "abc", text2 = "def" ;

输出:0

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

提示:

  • 1 <= text1.length <= 1000

  • 1 <= text2.length <= 1000 输入的字符串只含有小写英文字符。

二.动态规划的基本思想

动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果。

三.思路

动态规划五部曲

1.确定dp数组(dp table)以及下标的含义

dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]

有同学会问:为什么要定义长度为[0, i - 1]的字符串text1,定义为长度为[0, i]的字符串text1不香么?

这样定义是为了后面代码实现方便。

2.确定递推公式

主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同;

如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;

如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。

即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

代码如下:

if(text1[i -1]== text2[j -1])
{
    dp[i][j]= dp[i -1][j -1]+1;
}
else
  {
    dp[i][j]=max(dp[i -1][j], dp[i][j -1]);
  }

3.dp数组如何初始化

先看看dp[i][0]应该是多少呢?

test1[0, i-1]和空串的最长公共子序列自然是0,所以dp[i][0] = 0;

同理dp[0][j]也是0。

其他下标都是随着递推公式逐步覆盖,初始为多少都可以,那么就统一初始为0。

代码:

vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));

1

4.确定遍历顺序

从递推公式,可以看出,有三个方向可以推出dp[i][j],如图:

那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历这个矩阵。

5.举例推导dp数组

以输入:text1 = "abcde", text2 = "ace" 为例,dp状态如图:

最后红框dp[text1.size()][text2.size()]为最终结果

以上分析完毕,C++代码如下:

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
        for (int i = 1; i <= text1.size(); i++) {
            for (int j = 1; j <= text2.size(); j++) {
                if (text1[i - 1] == text2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[text1.size()][text2.size()];
    }
};

java

/*
    二维dp数组
*/
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int[][] dp = new int[text1.length() + 1][text2.length() + 1]; // 先对dp数组做初始化操作
        for (int i = 1 ; i <= text1.length() ; i++) {
            char char1 = text1.charAt(i - 1);
            for (int j = 1; j <= text2.length(); j++) {
                char char2 = text2.charAt(j - 1);
                if (char1 == char2) { // 开始列出状态转移方程
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[text1.length()][text2.length()];
    }
}



/**
    一维dp数组
*/
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int n1 = text1.length();
        int n2 = text2.length();

        // 多从二维dp数组过程分析  
        // 关键在于  如果记录  dp[i - 1][j - 1]
        // 因为 dp[i - 1][j - 1]  <!=>  dp[j - 1]  <=>  dp[i][j - 1]
        int [] dp = new int[n2 + 1];

        for(int i = 1; i <= n1; i++){

            // 这里pre相当于 dp[i - 1][j - 1]
            int pre = dp[0];
            for(int j = 1; j <= n2; j++){

                //用于给pre赋值
                int cur = dp[j];
                if(text1.charAt(i - 1) == text2.charAt(j - 1)){
                    //这里pre相当于dp[i - 1][j - 1]   千万不能用dp[j - 1] !!
                    dp[j] = pre + 1;
                } else{
                    // dp[j]     相当于   dp[i - 1][j]
                    // dp[j - 1] 相当于   dp[i][j - 1]
                    dp[j] = Math.max(dp[j], dp[j - 1]);
                }

                //更新dp[i - 1][j - 1], 为下次使用做准备
                pre = cur;
            }
        }

        return dp[n2];
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker----------day5---安装redis集群

1.哈希取余分区 2亿条记录就是2亿个k,v&#xff0c;我们单机不行必须要分布式多机&#xff0c;假设有3台机器构成一个集群&#xff0c;用户每次读写操作都是根据公式&#xff1a; hash(key) % N个机器台数&#xff0c;计算出哈希值&#xff0c;用来决定数据映射到哪一个节点上。…

华为机试题:HJ81 字符串字符匹配(python)

文章目录&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;Python3实现&#xff08;3&#xff09;知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

VO,BO,PO,DO,DTO,AO的区别

DTO&#xff08;Data Transfer Object&#xff09;数据传输对象 这个传输通常指的前后端之间的传输 1.在前端的时候&#xff1a; 存在形式通常是js里面的对象&#xff08;也可以简单理解成json&#xff09;&#xff0c;也就是通过ajax请求的那个数据体 2.在后端的时候&…

深入浅出C++ ——map类深度剖析

文章目录一、map类介绍二、map的使用三、multimap一、map类介绍 map是 C STL 中提供的容器&#xff0c;map是数学上的映射&#xff0c;其具有唯一性&#xff0c;即每个pair(key,value)只出现一次&#xff0c;而 multimap 则是可重复映射&#xff0c;两者的内部实现是一棵红黑树…

[Datawhale][CS224W]图机器学习(五)

这里写目录标题一、Deepwalk1.1 预备知识1.2 Deepwalk介绍1.3 Embedding1.4 word2Vec 词向量&#xff0c;词嵌入1.5 random Walk随机游走1.6 DeepWalk 核心代码Random WalkWord2vecDeepWalk应用1.7 DeepWalk优缺点二、Node2Vec2.1 图嵌入2.2 Node2Vec优化目标顶点序列采样策略2…

固态继电器控制电路

固态继电器控制电路 固态继电器&#xff08;SSR&#xff09;的种类和型号很多&#xff0c;因此其输入控制方法和控制电路也相应众多。固态继电器&#xff08;SSR&#xff09;的共同特点在于驱动电流或驱动电压小&#xff0c;即只需输入一个小信号即可控制SSR的开关。 如果需要…

瞎更新,container_cpu_usage_seconds_total{job=“cadvisor“} 怎么没有啦

一、 基本介绍 1.1 概论 1.1.1 故事背景 今天在同步其他团队的 grafana 监控大盘时&#xff0c;Prometheus 服务报告说不能找到名为 container_cpu_usage_seconds_total{job“cadvisor”} 的指标&#xff0c;一般来说可能有几个原因。 可能是 Prometheus 服务没开启prometh…

leaflet 实现极地标线地图,加载tileLayer.wms数据(088)

第088个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中实现极地标线地图,加载tileLayer.wms数据。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共93行)安装插件专栏目标相关API参考:示例效果…

什么是API?(详细解说)

编程资料时经常会看到API这个名词&#xff0c;网上各种高大上的解释估计放倒了一批初学者。初学者看到下面这一段话可能就有点头痛了。 API&#xff08;Application Programming Interface,应用程序编程接口&#xff09;是一些预先定义的函数&#xff0c;目的是提供应用程序与开…

超详细的阿里java岗社招知识点整理,常考知识点全在这里了

常考知识点 1、java的基本数据类型与包装类&#xff1b; 2、final修饰变量类方法&#xff1b; 3、String为什么是不可变的&#xff0c;以及new String(“abc”)创建了几个对象&#xff1b; 4、String、StringBuffer、以及StringBuilder的区别&#xff1b; 5、static修饰变…

金融BI分析的价值

众所周知&#xff0c;金融行业从信息化时代起&#xff0c;就是对IT依赖程度非常高的&#xff0c;也是最严苛的。进入到数字化时代&#xff0c;金融机构越来越注重技术创新&#xff0c;BI工具也越来越受到重视。利用BI工具&#xff0c;金融机构可以更快、更准确地获得有关市场信…

2023年1月用户体验GX评测:商业银行抢抓新春营销旺季,多措并举持续提升用户体验

易观&#xff1a;2023年1月正值中国传统春节营销旺季&#xff0c;各家银行充分发挥手机银行的优势&#xff0c;积极探索新春营销新模式&#xff0c;为客户提供极富特色的“开门红”线上营销活动&#xff0c;提升用户参与积极性&#xff0c;在用户体验上积极探索&#xff0c;增强…

真香!Linux 原来是这么管理内存的

Linux 内存管理模型非常直接明了&#xff0c;因为 Linux 的这种机制使其具有可移植性并且能够在内存管理单元相差不大的机器下实现 Linux&#xff0c;下面我们就来认识一下 Linux 内存管理是如何实现的。 一&#xff0c;基本概念 每个 Linux 进程都会有地址空间&#xff0c;这…

基于莱维飞行改进粒子群优化的长短期神经网络ispso-lstm的客流量预测,ISPSO-LSTM,神经网络1000案例之16

目录 摘要 背影 改进思路 shubett测试函数 函数代码 函数图像 测试ispso算法性能 测试代码 测试效果图像 ispso-lstm客流量预测 代码 测试效果 分析 展望 摘要 针对基本粒子群算法容易发生早熟收敛,陷入局部最优,等缺点,提出了基于莱维飞行的改进粒子群算法.在粒子位置更新公…

《计算机网络:自顶向下方法》实验5:TCP

Q1 包含HTTP POST消息的TCP报文段的序号是多少?注意:为了发现POST 命令, 你需要在wireshark底部的报文内容域窗口中去查找,查找数据中包含 “POST”的段。 如图所示,由报文中的POST 和 HTTP/1.1可知,其包含HTTP POST消息; TCP报文段的序号可见TCP报文: Sequence Number:…

win10输入法设置在哪里?对于输入法设置的图文教程

使用电脑打字&#xff0c;那么我们就会用到输入法。对于Windows电脑输入法的设置&#xff0c;很多用户都不知道如何调整。实际上&#xff0c;输入法设置就在“语言”选项里面&#xff0c;想要知道win10输入法设置的操作步骤&#xff0c;那就跟着小编的步伐来看看吧&#xff01;…

win10下 WSL2安装及配置

目录 一. Windows中WSL2&#xff08;子系统&#xff09;安装前提条件 二. Windows中WSL2&#xff08;子系统&#xff09;安装步骤&#xff08;默认安装C盘&#xff09; 选择包安装模式(选择到其他盘安装) 三. Windows中WSL2&#xff08;子系统&#xff09;设置默认root用户登…

数据结构——复杂度的详解(空间复杂度和时间复杂度)

1.程序算法效率 1.1什么是算法&#xff1f; 算法&#xff08;Algorithm&#xff09;是指解题方案的准确而完整的描述&#xff0c;是一系列解决问题的清晰指令&#xff0c;算法代表着用系统的方法描述解决问题的策略机制。 1.2衡量算法好坏的标准 这是一个通过函数递归算法实…

轻量级权限框架之-Sa-ToKen

轻量级的权限认证框架 Sa-Token 目前主要五大功能模块&#xff1a;登录认证、权限认证、单点登录、OAuth2.0、微服务鉴权 登录认证 —— 单端登录、多端登录、同端互斥登录、七天内免登录 权限认证 —— 权限认证、角色认证、会话二级认证 Session会话 —— 全端共享Session、…

Hadoop3 集群搭建

测试环境 信息内容主机版本centos7机器数量3台Hadoop版本3.3.4安装包解压路径/home/tools/hadoop/ hosts配置 主机ip地址对应主机host192.168.57.188node1192.168.57.189node2192.168.57.190node3 一. 前置环境准备 安装JDK1.8(Hadoop支持1.8)创建非root用户(这里用的myuser…