C国演义 [第七章]

第七章

  • 最长重复子数组
    • 题目理解
    • 步骤
      • dp含义
      • 递推公式
      • 初始化
        • 为啥dp数组如此奇怪
      • 遍历顺序
    • 代码
  • 最长公共子序列
    • 题目理解
    • 步骤
      • dp含义
      • 递推公式
      • 初始化
      • 遍历顺序
    • 代码
  • 总结

最长重复子数组

力扣链接

给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。

示例 1:
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。
示例 2:
输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0]
输出:5

  • 提示:
    1 <= nums1.length, nums2.length <= 1000
    0 <= nums1[i], nums2[i] <= 100

题目理解

暴力解法就是 用两个for循环遍历两个数组, 然后在套用一个while循环或者for循环从各个起始位置开始判断
这样就相当于套用了三个for循环, 数据大了就会超时

其实本题采用的方法是动态规划, 用个二维dp数组来记录比较情况

步骤

dp含义

重复子数组, 里面有个暗含意思 连续
dp[i][j] — — 以下标 i - 1为结尾的nums1, 以下标 j - 1 结尾的nums2 之间的最长重复子数组的长度

🗨️为啥是以 下标 i - 1结尾 而不是以下标 i 结尾呢??

  • 其实这也是为了方便初始化 和 后续的判断
    后面在 为啥dp数组如此奇怪 中有讲

递推公式

重复子数组, 里面有个暗含意思 连续
那么, 我们处理的方法 就和前面的 连续递增子序列 相同

if(nums1[i - 1] == nums2[j - 1])
	dp[i][j] = dp[i - 1][j - 1] + 1;

🗨️为啥比较的是 nums1[i - 1] 和 nums[j - 1], 而不是 nums1[i] 和 nums[j]呢

  • dp数组的含义是 以下标 i - 1为结尾的nums1, 以下标 j - 1 结尾的nums 之间的最长重复子数组的长度
    因为题目有 连续 的意思, 所以 dp[i][j] 的来源只有一个, 那就是 dp[i - 1][j - 1]
    条件就是判断 当前两数组的值是否相等 — — nums1[i - 1] == nums2[ j - 1]
    如果判断相等, 那么 dp[i][j] 就会在dp[i - 1][j - 1]的基础上 + 1 (两者都回退一步, 同时看看后面的值是否相等)

初始化


第一行 和 第一列要初始化一下.
那么我们需要初始化的是 dp[0][j] 和 dp[i][0]
但是, 我们定义的dp数组的含义 — — 以下标 i - 1为结尾的nums1, 以下标 j - 1 结尾的nums2 之间的最长重复子数组的长度
那么, 就是要初始化一下 -1行 和 -1列, 可想而知: 要初始化为 0
其它的要怎么初始化呢? — — 由前面到后面进行推导, 由上面到下面进行推导 — — 反正都是由前面的推导而来, 那么我们就初始化为 0

那么我们就全部都初始化为 0

 vector<vector<int>> dp (nums1.size() + 1, vector<int>(nums2.size() + 1, 0));

为啥dp数组如此奇怪

如果我们的dp数组的含义是 — — 以下标 i为结尾的nums1, 以下标 j为结尾的nums2之间的最长重复子数组的长度
那么, 初始化就要初始化 第1行 和 第 1列
如果nums1[i] 与 nums2[0] 相同的话,对应的 dp[i][0]就要初始为1, 因为此时最长重复子数组为1。 nums2[j] 与 nums1[0]相同的话,同理。

// 要对第一行,第一列经行初始化
for (int i = 0; i < nums1.size(); i++) if (nums1[i] == nums2[0]) dp[i][0] = 1;
for (int j = 0; j < nums2.size(); j++) if (nums1[0] == nums2[j]) dp[0][j] = 1;

遍历顺序


是从左上方开始递推的 — — 从前到后, 从上至下开始遍历

代码

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) 
    {
        vector<vector<int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
        
        int result = 0;
        for(int i = 1; i <= nums1.size(); i++)
        {
            for(int j = 1; j <= nums2.size(); j++)
            {
                if(nums1[i - 1] == nums2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                
                result = max(result, dp[i][j]);
            }

        }
        
        return result;

    }
};

在这里, 我们也给出 dp数组的含义是 — — 下标以 i - 1为结尾的nums1, 下标以 j - 1为结尾的nums2之间的最长重复子序列的长度👇👇👇

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) 
    {
        vector<vector<int>> dp(nums1.size(), vector<int>(nums2.size(), 0));
        
        // 要对第一行,第一列经行初始化
        for (int i = 0; i < nums1.size(); i++) if (nums1[i] == nums2[0]) dp[i][0] = 1;
        for (int j = 0; j < nums2.size(); j++) if (nums1[0] == nums2[j]) dp[0][j] = 1;
        
        int result = 0;
        for(int i = 0; i < nums1.size(); i++)
        {
            for(int j = 0; j < nums2.size(); j++)
            {
                if(i > 0 && j > 0 && nums1[i] == nums2[j]) // 为了预防i - 1 和 j - 1是负数
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                
                result = max(result, dp[i][j]);
            }

        }
        
        return result;

    }
};

最长公共子序列

力扣链接

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

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

例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列.
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列.

示例 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, text2.length <= 1000
    text1 和 text2 仅由小写英文字符组成

题目理解

这个题目是 不讲究连续 && 公共子序列
由此可以联想到 最长递增子序列
区别就是 : 一个是一个集合, 另一个是两个集合 — — 一个是一维dp数组, 另一个是二维dp数组

步骤

dp含义

dp[i][j] — — 区间为[0, i - 1]的nums1 和 区间为[0, j - 1]的nums2之间的最长公共子序列的长度
这里为啥是区间 i - 1 和 j - 1, 这个在上面已经说过了.

递推公式

无非就两种情况: nums1[i - 1] 和 nums2[j - 1] 是否相等

  • 如果nums1[i - 1] == nums2[j - 1] — — 那么就使用dp[i - 1][j - 1]的情况 — — dp[i - 1][j - 1] + 1
  • 如果nums1[i - 1] != nums2[j - 1] — — 那么就比较 区间为[0, i - 1]的nums1 和 区间为[0, j - 2]的nums2之间的最长公共子序列的长度(dp[i][j - 1]) 和 区间为[0, i - 2]的nums1 和 区间为[0, j - 1]的nums2之间的最长公共子序列的长度(dp[i - 1][j])
	if(nums1[i - 1] == nums2[j - 1])
		dp[i][j] = dp[i - 1][j - 1] + 1;
	else
		dp[i][j] = max(dp[i][j - 1], dp[i -1][j]);

初始化


通过递推公式可知, 我们要初始化第一行 和 第一列
即我们需要初始化的是 dp[0][j] 和 dp[i][0]
但是, 我们dp数组的含义是 — — 区间为[0, i - 1]的nums1 和 区间为[0, j - 1]的nums2之间的最长公共子序列的长度
那么, dp[0][j] 的含义就是 -1 行 — — 那就初始化为 0 , dp[i][0]亦是如此
那么, 其他的dp数组呢? — — 由前面递推过来的, 所以就初始化为 0也是可以的

所以, 我们就把 dp数组都初始化为 0

遍历顺序


通过递推公式可知, 是 从前到后, 从上至下的顺序 --- --- 从小到大的遍历顺序

代码

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][j - 1], dp[i - 1][j]);
            }

        }
        
        return dp[text1.size()][text2.size()];
    }
};

总结

通过前面几章的动态规划刷题篇的训练, 我们不难发现

  • dp数组的含义是非常重要的, 这也决定了后面的递推公式的得出
  • 递推公式涉及 i - 1 或者是 j - 1的, 建议从 1开始遍历好一些, 这样也避免了一些情况的讨论

贵有恒,何必三更起五更眠;最无益,只怕一日曝十日寒 — — 毛泽东

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

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

相关文章

初识express/路由/中间件

路由的概念 模块化路由 中间件(要有输入输出) 简化版本 全局生效中间件 局部生效中间件 注意事项 中间件分类 内置中间件,解析请求体/url-encoded 自定义中间件 使用querystring模块解析请求体数据 编写接口 ​​​​​​​

希尔排序(C语言)

希尔排序 一、希尔排序的原理二、动图演示三、代码实现四、实现从小到大排序五、希尔排序的优缺点 一、希尔排序的原理 希尔排序是插入排序的一种更高效的改进版本。 1.将原始待排数据按照设定的增量gap分成多组&#xff0c;每组有n / gap个元素。 2.对这些分组进行插入排序&a…

单表-DQL

注意&#xff1a;这张图还包含了对于的顺序&#xff0c;先分组再排序&#xff0c;再分页&#xff0c;顺序不能乱 基本查询 # 1.基本查询 # 查询全部行 select * from tb_emp; select id, user_name, password, name, gender, image, job, entry_date, create_time, update_ti…

yarn与npm的区别(yarn的安装报错问题)

一、yarn 是什么&#xff0c;yarn 与 npm 的区别是什么&#xff1f; yarn 是一个软件包管理系统&#xff0c;Yarn 和 npm 都是包管理工具&#xff0c;用于管理用 JavaScript 编写的软件包&#xff0c;yarn的出现是为了弥补 npm的一些缺陷。yarn 与 npm 的区别 &#xff1a; 性能…

MongoDB复制集原理

复制集简介 Mongodb复制集由一组Mongod实例&#xff08;进程&#xff09;组成&#xff0c;包含一个Primary节点和多个Secondary节点&#xff0c;Mongodb Driver&#xff08;客户端&#xff09;的所有数据都写入Primary&#xff0c;Secondary从Primary同步写入的数据&#xff0…

3.springboot开发篇

SpringBoot开发实用篇 ​ KF-1.热部署 热部署是不用重启项目&#xff0c;项目自动更新 非springboot项目热部署实现原理 ​ 开发非springboot项目时&#xff0c;我们要制作一个web工程并通过tomcat启动&#xff0c;通常需要先安装tomcat服务器到磁盘中&#xff0c;开发的程序…

密码学证明方案寒武纪大爆发——扩容、透明性和隐私的变革潜力

1. 引言 前序博客有&#xff1a; ZKP大爆炸 本文主要参考&#xff1a; StarkWare 2023年6月博客 Cambrian Explosion of Cryptographic Proofs----The transformative potential for scalability, transparency, and privacy2023年3月Eli Ben-Sasson在The 13th BIU Winter …

vmware postgresql大杂烩

Vmware 窗口过界&#xff1a; https://blog.csdn.net/u014139753/article/details/111603882 vmware, ubuntu 安装&#xff1a; https://zhuanlan.zhihu.com/p/141033713 https://blog.csdn.net/weixin_41805734/article/details/120698714 centos安装&#xff1a; https://w…

形式化验证,QED: Quick Error Detection Tests for Effective Post-Silicon Validation(二)

目录 一、Article:文献出处&#xff08;方便再次搜索&#xff09; &#xff08;1&#xff09;作者 &#xff08;2&#xff09;文献题目 &#xff08;3&#xff09;文献时间 &#xff08;4&#xff09;引用 二、Data:文献数据&#xff08;总结归纳&#xff0c;方便理解&am…

抖音短视频矩阵系统源码:技术开发与实践

目录 一.短视频账号矩阵管理系统囊括的技术 1.开发必备的开发文档说明&#xff1a; 二.技术文档分享&#xff1a; 1.底层框架系统架构&#xff1a; 2.数据库接口设计 1.技术开发必备的开发文档说明&#xff1a; 1.1系统架构&#xff1a; 抖音SEO排名系统主要由以下几个模…

Spring Boot 属性加载原理解析

基于Spring Boot 3.1.0 系列文章 Spring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解Spring Boot 监听器详解Spring Boot banner详解Spring Boot 属性配置解析Spring Boot 属性加载原理解析 在《Spring Boot 框架整体启动流程详…

【计算机视觉 | 图像分类】arxiv 计算机视觉关于图像分类的学术速递(6月 29 日论文合集)

文章目录 一、分类|识别相关(12篇)1.1 Pseudo-Bag Mixup Augmentation for Multiple Instance Learning Based Whole Slide Image Classification1.2 Improving Primate Sounds Classification using Binary Presorting for Deep Learning1.3 Challenges of Zero-Shot Recognit…

阿里云docker启动xxljob,部署自己的定时任务

本次安装版本xxl-job-admin:2.3.0 一&#xff1a;创建xxl-job数据库的各种表 作者官方地址 下载sql执行 二&#xff1a;docker拉取xxl-job镜像 docker pull xuxueli/xxl-job-admin:2.3.0 三&#xff1a;docker启动xxl-job服务 docker run -e PARAMS"--spring.datasour…

Tensorflow神经网络模型-鲜花种类识别

必应壁纸供图 Tensorflow神经网络模型-鲜花种类识别 数据集&#xff1a;https://download.csdn.net/download/weixin_53742691/87982215 导入相关依赖 import warnings import re from IPython.display import clear_output, display from tkinter import Tk, filedialog fro…

wampServer安装Redis 扩展

第一步&#xff1a;查看php版本信息 使用 phpinfo() 函数查看 PHP 的版本信息&#xff08;用于选择扩展包&#xff09; 版本信息&#xff1a;PHP版本为 8.0.26&#xff0c;编译器版本 Visual C 2019&#xff0c;CPU架构 x64 。 第二步&#xff1a;根据第一步信息的版本选择扩…

基于树莓派4B的YOLOv5-Lite目标检测的移植与部署(含训练教程)

前言&#xff1a;本文为手把手教学树莓派4B项目——YOLOv5-Lite目标检测&#xff0c;本次项目采用树莓派4B&#xff08;Cortex-A72&#xff09;作为核心 CPU 进行部署。该篇博客算是深度学习理论的初步实战&#xff0c;选择的网络模型为 YOLOv5 模型的变种 YOLOv5-Lite 模型。Y…

【AI底层逻辑】——篇章3(上):数据、信息与知识香农信息论信息熵

目录 引入 一、数据、信息、知识 二、“用信息丈量世界” 1、香农信息三定律 2、一条信息的价值 3、信息的熵 总结 引入 AI是一种处理信息的模型&#xff0c;我们把信息当作一种内容的载体&#xff0c;计算机发明以前很少有人思考它的本质是什么。随着通信技术的发展&a…

【ISO26262】汽车功能安全第3部分:概念阶段

GB/T34590《道路车辆 功能安全》分为以下部分: 需要文档的朋友,可以和我联系! tommi_wei@163.com GB/T34590的本部分规定了车辆在概念阶段的要求: ———相关项定义; ———安全生命周期启动; ———危害分析和风险评估;及 ———功能安全概念。 危害事件分类 对于每一个…

wsl子系统Ubuntu18.04,cuDNN安装

如果觉得本篇文章对您的学习起到帮助作用&#xff0c;请 点赞 关注 评论 &#xff0c;留下您的足迹&#x1f4aa;&#x1f4aa;&#x1f4aa; 本文主要wls子系统Ubuntu18.04安装cuDNN&#xff0c;安装cudnn坑巨多&#xff0c;因此记录以备日后查看&#xff0c;同时&#xff0…

GaussDB WDR报告分析

标题 问题描述问题现象告警业务影响原因分析处理方法步骤 1步骤 2步骤 3步骤 4步骤 6步骤 7步骤 8步骤9步骤 10步骤 11步骤 12 问题描述 CPU使用率高。 问题现象 出现CPU使用率超过阈值&#xff0c;CPU使用率快速上涨或短时间持续较高水平等现象。 告警 CPU使用率告警。 …