LeetCode算法题解(动态规划)|LeetCode1143. 最长公共子序列、LeetCode1035. 不相交的线、LeetCode53. 最大子数组和

news2025/2/27 11:23:45

一、LeetCode1143. 最长公共子序列

题目链接:1143. 最长公共子序列
题目描述:

给定两个字符串 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[i][j]表示在区间[0,i]之间的text1字符串,与区间[0,j]的text2字符串最长的公共子序列长度。

递推公式:

如果字符text[i]与字符text2[j]相等,那么dp[i][j]可由dp[i-1][j-1]推出来,即[0,i]之间的text1字符串与[0,j]之间text2字符串的最长公共子序列长度等于,[0,i-1]之间的text1字符串与[0,j-1]之间的text2字符串的最长公共子序列长度加一。

如果不相等,那么dp[i][j]可由两个方向推导出来:

1、[0,i-1]之间的text1字符串与[0,j]之间的text2字符串的最长公共子序列长度。

2、[0,i]之间的text1字符串与[0,j-1]之间的text2字符串的最长公共子序列长度。

所以dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

初始化:

因为dp[i][j]是由dp[i-1][j-1],dp[i-1][j],dp[i][j-1]三个方向推出来的,所以需要初始化最左边一列和最上边那一行。

        for(int i = 0; i < text2.length(); i++){//如果dp[0][i]被初始化成1,那么后面的都需初始化成1
            if(text1.charAt(0) == text2.charAt(i)){
                dp[0][i] = 1;
            }else if(i == 0){
                dp[0][i] = 0;
            }else{
                dp[0][i] = dp[0][i-1];
            }
        }
        for(int i = 0; i < text1.length(); i++){//如果dp[i][0]被初始化成1,那么后面的都需初始化成1
            if(text1.charAt(i) == text2.charAt(0)){
                dp[i][0] = 1;
            }else if(i == 0){
                dp[i][0] = 0;
            }else{
                dp[i][0] = dp[i-1][0];
            }
        }
遍历顺序:

先遍历text1再遍历text2或先遍历text2再遍历text1都可以,不过都需从下标1开始往后遍历。

打印dp数组进行验证。

代码如下:

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int[][] dp = new int[text1.length()][text2.length()];
        for(int i = 0; i < text2.length(); i++){
            if(text1.charAt(0) == text2.charAt(i)){
                dp[0][i] = 1;
            }else if(i == 0){
                dp[0][i] = 0;
            }else{
                dp[0][i] = dp[0][i-1];
            }
        }
        for(int i = 0; i < text1.length(); i++){
            if(text1.charAt(i) == text2.charAt(0)){
                dp[i][0] = 1;
            }else if(i == 0){
                dp[i][0] = 0;
            }else{
                dp[i][0] = dp[i-1][0];
            }
        }
        for(int i = 1; i < text1.length(); i++) {
            for(int j = 1; j < text2.length(); j++) {
                if(text1.charAt(i) == text2.charAt(j)){
                    dp[i][j] = dp[i-1][j-1]+1;
                }else{
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        // for(int i = 0; i < text1.length(); i++) {
        //     for(int j = 0; j < text2.length(); j++) {
        //         System.out.print(dp[i][j]+" ");
        //     }
        //     System.out.println();
        // }
        return dp[text1.length()-1][text2.length()-1];
    }
}

二、LeetCode1035. 不相交的线

题目链接:1035. 不相交的线
题目描述:

在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。

现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足满足:

  •  nums1[i] == nums2[j]
  • 且绘制的直线不与任何其他连线(非水平线)相交。

请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。

以这种方法绘制线条,并返回可以绘制的最大连线数。

示例 1:

输入:nums1 = [1,4,2], nums2 = [1,2,4]
输出:2
解释:可以画出两条不交叉的线,如上图所示。 
但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。

示例 2:

输入:nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2]
输出:3

示例 3:

输入:nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1]
输出:2

提示:

  • 1 <= nums1.length, nums2.length <= 500
  • 1 <= nums1[i], nums2[j] <= 2000
算法分析:

这道题的思路其实跟上一道题是一模一样的,要求可以绘制的不相交的最大连线数,也就是求两个数组的最大公共子序列。

定义dp数组及下标含义:

dp[i][j]表示[0,i]区间的nums1子数组和[0,j]区间的nums2子数组的最长公共子序列。

递推公式:

如果nums1[i]与nums2[j]相等,那么dp[i][j]=dp[i-1][j-1]+1;

如果不相等那么dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

初始化:

初始化第一列和第一行。

        for(int i = 0; i < nums1.length; i++) {
            if(nums1[i] == nums2[0]){
                dp[i][0] = 1;
            }else if(i == 0){
                dp[i][0] = 0;
            }else{
                dp[i][0] = dp[i-1][0];
            }
        }
        for(int i = 0; i < nums2.length; i++) {
            if(nums2[i] == nums1[0]){
                dp[0][i] = 1;
            }else if(i == 0){
                dp[0][i] = 0;
            }else{
                dp[0][i] = dp[0][i-1];
            }
        }
遍历顺序:

先遍历nums1在遍历nums2或先遍历nums2在遍历nums1都可以。

打印dp数组验证。

代码如下:

class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int[][] dp = new int[nums1.length][nums2.length];
        for(int i = 0; i < nums1.length; i++) {
            if(nums1[i] == nums2[0]){
                dp[i][0] = 1;
            }else if(i == 0){
                dp[i][0] = 0;
            }else{
                dp[i][0] = dp[i-1][0];
            }
        }
        for(int i = 0; i < nums2.length; i++) {
            if(nums2[i] == nums1[0]){
                dp[0][i] = 1;
            }else if(i == 0){
                dp[0][i] = 0;
            }else{
                dp[0][i] = dp[0][i-1];
            }
        }
        for(int i = 1; i < nums1.length; i++) {
            for(int j = 1; j < nums2.length; j++) {
                if(nums1[i] == nums2[j]){
                    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[nums1.length-1][nums2.length-1];

    }
}

三、LeetCode53. 最大子数组和

题目链接:53. 最大子数组和
题目描述:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
算法分析:
定义dp数组及下标含义:

dp[i]表示以nums[i]结尾的子序列的最大和。

递推公式:

dp[i]可以由两个方向推出来,一个是dp[i-1]+nums[i],以nums[i-1]结束的子序列的最大和加上第i个元素;两一个是nums[i],重新开始一段子序列和。

初始化:

dp[0]=nums[0]。

遍历顺序:

从前往后遍历数组中的元素。

打印dp数组。

代码如下:

class Solution {
    public int maxSubArray(int[] nums) {
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int result = dp[0];//记录最大的子数组和。
        for(int i = 1; i < nums.length; i++){
            dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
            if(dp[i] > result) result = dp[i];
        }
        return result;

    }
}

总结

前两道题很类似,只要会其中一道题,另外一道题也会迎刃而解。

第三题暴力算的话会超时,动规也不容易想出来。

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

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

相关文章

四、设置主机名和域名映射

目录 1、配置每台虚拟机主机名 2、配置每台虚拟机域名映射 1、配置每台虚拟机主机名

Unity对接后台和加载图片

1、前言 在unity中与后台对接&#xff0c;用await在web端暂时还不支持&#xff0c;所以&#xff0c;协程成为比较好的通用方式&#xff0c;以下适用除post访问外的所有对接 2、对接后台 2.1、安装插件 首先我们需要用到Newtonsoft.dll&#xff0c;如果没有这个.dll的请跟着我…

vue权限管理解决方案

一. 什么是权限管理 权限控制是确保用户只能访问其被授权的资源和执行其被授权的操作的重要方面。而前端权限归根结底是请求的发起权&#xff0c;请求的发起可能有下面两种形式触发 页面加载触发页面上的按钮点击触发 总体而言&#xff0c;权限控制可以从前端路由和视图两个…

QProcess 启动 进程 传参数 启动控制台进程 传参

目录 QProcess 启动外部程序的两种方式 依赖式 分离式&#xff1a; 启动进程前的预处理 设置启动路径 设置启动命令参数 设置启动工作目录 设置启动所需环境&#xff1a; 启动的状态 code smple: QProcess 控制台进程 QProcess启动控制台不显示窗口 注意&#xff1a;…

jvm基本概念,运行的原理,架构图

文章目录 JVM(1) 基本概念:&#xff08;2&#xff09;运行过程 今天来和大家聊聊jvm&#xff0c; JVM (1) 基本概念: JVM 是可运行Java代码的假想计算机&#xff0c;包括一套字节码指令集、一组寄存器、一个栈一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作…

9.ROS的TF坐标变换(三):坐标系关系查看与一个案例

1 查看目前的坐标系变化 我们先安装功能包&#xff1a; sudo apt install ros-melodic-tf2-tools安装成功&#xff01; 我们先启动上次的发布坐标变换的节点&#xff1a; liuhongweiliuhongwei-Legion-Y9000P-IRX8H:~/Desktop/final/my_catkin$ source devel/setup.bash liuho…

cyclictest 交叉编译与使用

目录 使用版本问题编译 numactl编译 cyclictest使用参考 cyclictest 主要是用于测试系统延时&#xff0c;进而判断系统的实时性 使用版本 rt-tests-2.6.tar.gz numactl v2.0.16 问题 编译时&#xff0c;需要先编译 numactl &#xff0c;不然会有以下报错&#xff1a; arm-…

Linux:优化原则

web系统的优化原则&#xff1a; 从单机到集群 对Linux系统自身的优化原则&#xff1a;

TCP报文解析

1.端口号 标记同一台计算机上的不同进程 源端口&#xff1a;占2个字节&#xff0c;源端口和IP的作用是标记报文的返回地址。 目的端口&#xff1a;占2个字节&#xff0c;指明接收方计算机上的应用程序接口。 TCP报头中的源端口号和目的端口号同IP报头中的源IP和目的IP唯一确定一…

【QT】Windows环境下,cmake引入QML

这里使用的QT库为5.7版本。 1、添加环境变量 QT库根目录环境变量 QTDIR QT库平台插件环境变量 QT_PLUGIN_PATH QML支持环境变量 QML2_IMPORT_PATH &#xff08;该环境变量仅在需要使用QML时添加&#xff09; QT库动态库环境变量&#xff0c;bin目录下包含了QT程序运行所需的dl…

电子学会C/C++编程等级考试2022年03月(四级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:拦截导弹 某国为了防御敌国的导弹袭击, 发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷: 虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。 某天, 雷达捕捉到敌国的导弹来袭。…

第十一届蓝桥杯青少组省赛Python中高级组真题及赏析

练习最好的办法就是实战。拿真题来做&#xff0c;不是解析是赏析。带着欣赏的眼光看&#xff0c;题目不但不难&#xff0c;反倒增加不少乐趣。接下来揭开第十一届蓝桥杯青少组省赛python编程题的神秘面纱&#xff0c;我们来一一赏析&#xff0c;看难不难。 选择题 选择题都比较…

C++核心编程——类与对象基础

C核心编程——类与对象基础 类与对象封装构造函数普通构造拷贝构造初始化成员列表&#xff08;补充&#xff09; 析构函数对象数组对象指针指向对象的指针指向对象成员的指针this指针 静态成员静态数据成员静态成员函数 友元普通函数做友元函数友元成员函数友元类 类与对象 C面…

深度学习常见回归分支算法逐步分析,各种回归之间的优缺点,适用场景,举例演示

文章目录 1、线性回归&#xff08;Linear Regression&#xff09;1.1 优点1.2 缺点1.3 适用场景1.4 图例说明 2、多项式回归&#xff08;Polynomial Regression&#xff09;2.1 优点2.2 缺点2.3 适用场景2.4 图例说明 3、决策树回归&#xff08;Decision Tree Regression&#…

Linux基础命令(超全面,建议收藏!)

一、Linux的目录结构 /&#xff0c;根目录是最顶级的目录了 Linux只有一个顶级目录&#xff1a;/ 路径描述的层次关系同样使用/来表示 /home/itheima/a.txt&#xff0c;表示根目录下的home文件夹内有itheima文件夹&#xff0c;内有a.txt 二、Linux命令基础格式 无论是什么…

孩子都能学会的FPGA:第十八课——用FPGA实现定点数的除法

&#xff08;原创声明&#xff1a;该文是作者的原创&#xff0c;面向对象是FPGA入门者&#xff0c;后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门&#xff0c;作者不光让大家知其然&#xff0c;还要让大家知其所以然&#xff01;每个工程作者都搭建了全自动化的仿…

vivado实现分析与收敛技巧6-策略建议

典型时序收敛策略需运行大量实现策略并选取其中最佳的策略以供在实验室内应用。 ML 策略同样可选 &#xff0c; 且只需您运行3 项策略即可达成类似的 QoR 收益。这些策略使用机器学习来检验布线后设计的各项功能特性 &#xff0c; 以便预测相同设计上不同策略的性能。在 repo…

树莓派4b安装ubuntu22和向日葵设置开机启动

树莓派4b安装ubuntu22和向日葵设置开机启动 使用树莓派烧录系统工具烧录ubuntu 在树莓派官网下载官方软件&#xff0c;安装完后运行 在软件上选择 选择ubuntu桌面或者server 根据自己需求选择&#xff0c;这里我选择22.04的系统 烧录好以后进入系统 安装向日葵 下载树莓…

Android实验:启动式service

目录 实验目的实验内容实验要求项目结构代码实现结果展示 实验目的 充分理解Service的作用&#xff0c;与Activity之间的区别&#xff0c;掌握Service的生命周期以及对应函数&#xff0c;了解Service的主线程性质&#xff1b;掌握主线程的界面刷新的设计原则&#xff0c;掌握启…

如何在WordPress中批量替换图片路径?

很多站长在使用WordPress博客或者搬家时&#xff0c;需要把WordPress文章中的图片路径进行替换来解决图片不显示的问题。总结一下WordPress图片路径批量替换的过程&#xff0c;方便有此类需求的站长们学习。 什么情况下批量替换图片路径 1、更换了网站域名 有许多网站建设初期…