LeetCode算法题解(动态规划)|LeetCode392. 判断子序列、LeetCode115. 不同的子序列

一、LeetCode392. 判断子序列

题目链接:392. 判断子序列
题目描述:

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

示例 1:

输入:s = "abc", t = "ahbgdc"
输出:true

示例 2:

输入:s = "axc", t = "ahbgdc"
输出:false

提示:

  • 0 <= s.length <= 100
  • 0 <= t.length <= 10^4
  • 两个字符串都只由小写字符组成。
算法分析:
定义dp数组及下标含义:

dp[i][j]表示字符串s第i个下标之前的子串,与字符串t第j个下标之前的子串,相同的子序列长度。

递推公式:

如果s[i] == s[j],那么dp[i][j]可以由dp[i-1][j-1]+1推出来,

[0,i]区间的s子串与[0,j]区间的t子串相同的子序列长度等于[0,i-1]区间的s子串和[0,j-1]区间的t子串相同的子串序列长度加一;

如果s[i] != s[j],那么dp[i][j] 可以有两个方向推出来:

1、[0,i-1]区间的s子串与[0,j]区间的t子串的相同子序列的长度;

2、[0,i]区间的s子串与[0,j-1]区间的t子串的相同子序列的长度;

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

初始化:

根据递推公式dp[i][j]=dp[i-1][j-1],dp[i][j]=max(dp[i-1][j],dp[i][j-1]),dp[i][j]可由它的左方、上方和左上放推出来,所以需要初始化dp数组的左边那一列和上边那一行。

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

字符串s和t的遍历顺序无所谓,不过都需从前往后遍历。

打印dp数组验证。(省略)

代码如下:

class Solution {public boolean isSubsequence(String s, String t) {if(s.length() == 0) return true;if(t.length() == 0) return false;int[][] dp = new int[s.length()][t.length()];for(int i = 0; i < t.length(); i++){if(s.charAt(0) == t.charAt(i)){dp[0][i] = 1;}else if(i > 0){dp[0][i] = dp[0][i-1];}else{dp[0][i] = 0;}}for(int i = 0; i < s.length(); i++){if(s.charAt(i) == t.charAt(0)){dp[i][0] = 1;}else if(i > 0){dp[i][0] = dp[i-1][0];}else{dp[i][0] = 0;}}for(int i = 1; i < s.length(); i++) {for(int j = 1; j < t.length(); j++) {if(s.charAt(i) == t.charAt(j)){dp[i][j] = dp[i-1][j-1] + 1;}else{dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]);}}}if(dp[s.length()-1][t.length()-1] == s.length()) return true;return false;}
}

二、LeetCode115. 不同的子序列

题目链接:115. 不同的子序列
题目描述:

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 109 + 7 取模。

示例 1:

输入:s = "rabbbit", t = "rabbit"
输出3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案rabbbit
rabbbit
rabbbit

示例 2:

输入:s = "babgbag", t = "bag"
输出5
解释:
如下所示, 有 5 种可以从 s 中得到 "bag" 的方案babgbag
babgbag
babgbag
babgbag
babgbag

提示:

  • 1 <= s.length, t.length <= 1000
  • s 和 t 由英文字母组成
算法分析:
定义dp数组及下标含义:

dp[i][j]表示以下标i结束的t字符串在以下标j结尾的s字符串中出现的次数。

递推公式:

当t[i] == s[j]时,dp[i][j]由两个部分组成:

1、用s[j]来匹配,那么dp[i][j] = dp[i-1][j-1];

以当前元素做结尾,那么dp[i][j] = dp[i-1][j-1]; 以j结尾的s字符串中出现的以i结尾的t字符串的次数就等于以j-1结尾的s字符串中出现的以i-1结尾的t字符串出现的次数。

2、不用s[j]来匹配,那么dp[i][j] = dp[i][j-1];

所以dp[i][j] = dp[i-1][j-1] + dp[i][j-1],注意这里是两种情况都可以不是只能选一种,所以总情况要加起来。

例如:s ="bagg",t ="bag";

s[3]和t[2]是相等的,s可以用s[4]来匹配,也即t由s[0]s[1]s[3]组成,

也可以不用s[4]来匹配,即t由s[0]s[1]s[2]组成。

所以当t[i] == s[j] 时,dp[i][j] = dp[i-1][j-1]+dp[i][j-1];

当t[i] != s[j]时,dp[i][j]只有一部分组成:

那就是不用s[j]匹配,即dp[i][j]=dp[i][j-1];

初始化:

根据递推公式我们需要初始化第一行dp[0][j],也就是s当中出现的t[0]元素的个数。

        for(int j = 0; j < s.length(); j++){//dp[0][j]表示以j结尾的s字符串当中t[0]出现的个数if(t.charAt(0) != s.charAt(j)){if(j == 0) dp[0][j] = 0;else dp[0][j] = dp[0][j-1];}else{if(j == 0) dp[0][j] = 1;else dp[0][j] = dp[0][j-1] + 1;}}
遍历顺序:

先遍历字符串t在遍历字符串s或先遍历s再遍历t都可以,不过都须从前往后遍历。

打印dp数组进行验证。

代码如下:

class Solution {public int numDistinct(String s, String t) {int[][] dp = new int[t.length()][s.length()];//dp[i][j]表示以下标j结尾的s字符串当中出现的以i结尾的t字符串的个数for(int j = 0; j < s.length(); j++){//初始化第一行if(t.charAt(0) != s.charAt(j)){if(j == 0) dp[0][j] = 0;else dp[0][j] = dp[0][j-1];}else{if(j == 0) dp[0][j] = 1;else dp[0][j] = dp[0][j-1] + 1;}}for(int j = 1; j < s.length(); j++) {for(int i = 1; i < t.length(); i++) {if(t.charAt(i) == s.charAt(j)){dp[i][j] = dp[i-1][j-1] + dp[i][j-1];}else{dp[i][j] = dp[i][j-1];}}}// for(int i = 0; i < t.length(); i++) {//     for(int j = 0; j < s.length(); j++) {//        System.out.print(dp[i][j] + " ");//     }//     System.out.println();// }return dp[t.length()-1][s.length()-1];}
}

总结

第二题还是比较困难的,对于dp[i][j]的递推公式不容易想到。

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

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

相关文章

一文看懂 Linux 内核,清晰明了

Linux内核预备工作 理解Linux内核最好预备的知识点&#xff1a;懂C语言 懂一点操作系统的知识 熟悉少量相关算法 懂计算机体系结构 Linux内核的特点&#xff1a; 结合了 unix 操作系统的一些基础概念。 Linux内核的任务&#xff1a; 1. 从技术层面讲&#xff0c;内核是硬…

ESP32 LVGL Gui-Guider的移植

使用参考&#xff1a; ESP32系列之LVGL&#xff08;三&#xff09;&#xff1a;Gui-Guider的使用_esp32 lvgl-CSDN博客 1、拷贝文件&#xff1a; 按照上面的文章&#xff0c;使用Gui-Guider软件生成C代码之后&#xff0c;custom和generated是我们要使用到的文件&#xff0c;…

阿里云服务器租赁价格表,预算100元到5000元可选配置

阿里云服务器租用费用&#xff0c;阿里云轻量应用服务器2核2G3M带宽轻量服务器一年87元&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;ECS云服务器e系列2核2G配置3M固定带宽99元一年、2核4G配置365元一年、2核8G配置522元一年&#xff0c;阿里云u1服务器2核4G、…

成为Java开发高手:掌握Spring框架的关键技能-DI

DI相关内容 1.1 setter注入1.1.2 注入引用数据类型1.1.3 注入简单数据类型步骤1:声明属性并提供setter方法步骤2:配置文件中进行注入配置步骤3:运行程序 1.2 构造器注入1.2.2 构造器注入引用数据类型步骤1:删除setter方法并提供构造方法步骤2:配置文件中进行配置构造方式注入步…

最优化理论复习--凸集与凸函数

文章目录 基本概念凸集凸函数下一篇 基本概念 可行点&#xff08;可行解&#xff09;&#xff1a;在规划问题中&#xff0c;满足约束条件的点可行集或可行域&#xff1a;全体可行点组成的集合无约束问题&#xff1a;如果一个问题的可行集是整个空间。 分为三种情况&#xff1…

甘草书店记:6# 2023年10月31日 星期二 「梦想从来不是一夜之间实现的」

甘草书店 今天收到甘草书店第二版装修设计平面图&#xff0c;与理想空间越来越近。 于我而言&#xff0c;每一次世俗意义上所谓的成功都不如文艺作品中表现的那样让人欢腾雀跃。当你用尽120分努力&#xff0c;达到了冲刺满分的实力时&#xff0c;得个优秀的成绩也并不意外。 …

华为云obs在java中的使用

1、申请obs服务。 申请完成后&#xff0c;会获得以下几个配置信息&#xff1a; AK"****************************"; SK"******************************************************"; ENDPOINT"obs.*************************"; BUCKET_NAME&q…

二维码智慧门牌管理系统升级解决方案:优化制牌存疑管理

文章目录 前言一、解决方案关键特点二、解决方案的优势 前言 二维码智慧门牌管理系统在城市管理中发挥着重要作用&#xff0c;然而&#xff0c;制牌审核过程中遇到存疑地址数据是常见问题&#xff0c;需要更有效的处理方法。为此&#xff0c;我们提出了二维码智慧门牌管理系统…

JDK、JRE、JVM、SE、EE、ME的区别

一、JDK Java Development Kit&#xff0c;Java 软件开发工具包。JDK是提供给Java开发人员使用的&#xff0c;包含了JRE和一些Java开发工具&#xff0c;如编译工具&#xff08;javac.exe&#xff09;、打包工具&#xff08;jar.exe&#xff09;等。所以安装了JDK就不需…

Swift 如何实现自定义 Tab Bar

前言 每个 UI 设计师都喜欢美丽而有动画效果的 Tab Bar。然而&#xff0c;对于开发人员来说&#xff0c;实现这种设计可能是一场噩梦。当然&#xff0c;使用 Apple 的原生 Tab Bar 组件并专注于更有趣的事情&#xff0c;比如业务逻辑的实现&#xff0c;会更容易。但如果我们必…

用金鸣识别实现纸质合同转word的几个解决方案

合同是我们日常生活和工作中经常碰到的文件类型&#xff0c;如果您需要将纸合同转为可编辑的Word文档怎么办呢&#xff1f; 如果是一般无表格的合同比较好处理&#xff0c;一般的OCR软件都能应付&#xff0c;只是识别率高低的问题&#xff08;好的OCR识别率高&#xff0c;后期…

用js自定义一个(v-model)vModel双向绑定函数

vue中的v-model是双向绑定的, 我们自己用JavaScript实现一个双向绑定vModel函数。 // element 元素或者#id,.class,div 得是input标签 // data 对象 // 将要绑定property 对象中的key<input class"vmodel"/>function vModel(element, data, property) {if (…

优雅草蜻蜓I即时通讯·水银版私有化部署之java服务端搭建教程-01

目录 前言1 1 安装 mongodb2 2 安装 redis3 3. 安装jdk3 4 解压 spring-boot-imapi3 5.开始安装 消息队列组件 rocket4 6. 安装推送服务5 7. 安装 message-push5 8. 安装uplooad 服务5 9&#xff1a; 安装nginx 服务7 1.不需要SSL7 2.需要SSL7 五&#xff1a;编译…

深入理解JVM中的即时编译器(JIT)

Java 虚拟机&#xff08;JVM&#xff09;是一种让 Java 程序能够运行在不同硬件平台上的技术&#xff0c;其中即时编译器&#xff08;JIT&#xff0c;Just-In-Time Compiler&#xff09;是其最为核心的优化技术之一。JVM之所以能够提高Java应用程序的性能&#xff0c;与JIT的密…

LORA概述: 大语言模型的低阶适应

LORA概述: 大语言模型的低阶适应 LORA: 大语言模型的低阶适应前言摘要论文十问实验RoBERTaDeBERTaGPT-2GPT-3 结论代码调用 LORA: 大语言模型的低阶适应 前言 LoRA的核心思想在于优化预训练语言模型的微调过程&#xff0c;通过有效地处理权重矩阵的变化&#xff08;即梯度更新…

常用sql记录

备份一张表 PostgreSQL CREATE TABLE new_table AS SELECT * FROM old_table;-- 下面这个比上面好&#xff0c;这个复制表结构时&#xff0c;会把默认值、约束、注释都复制 CREATE TABLE new_table (LIKE old_table INCLUDING ALL) WITHOUT OIDS; INSERT INTO new_table SELE…

极智芯 | 解读国产AI算力 璧仞产品矩阵

欢迎关注我,获取我的更多经验分享 大家好,我是极智视界,本文分享一下 解读国产AI算力 璧仞产品矩阵。 璧仞在国产 AI 芯领域就是 "迷" 一样的存在,你要说它在市场上的 "建树" 泛善可陈的话,它又 "赫然" 在美国芯片禁令名单中。而这一切的一…

Vue2学习笔记(列表渲染)

案例由浅到深&#xff0c;逐步深入。 一 、案例1&#xff1a;v-for的使用方法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scal…

跨网文件摆渡系统:安全、可控的数字传输桥梁

在企业高度信息化的时代&#xff0c;数据的流通与共享已经成为企业、组织乃至个人之间不可或缺的沟通方式。然而&#xff0c;在数据流通的过程中&#xff0c;我们经常会遇到各种难题和挑战&#xff0c;尤其是当涉及到不同网络环境之间的文件传输。这不仅需要保证文件的安全性&a…

MySQL的多表查询

<!DOCTYPE html> <html> <head> <meta charset"UTF-8" /> <title>多表查询</title> </head> <body> <!-- 多表关系 概述&#xff1a;基本上分为三种&#xff1a; 一对多&#xff08;多对一&#xff09; 案例…