class068 更多的动态规划【算法】

class068 更多的动态规划【算法】

算法讲解068【必备】见识更多二维动态规划题目

在这里插入图片描述

code1 115. 不同的子序列

// 不同的子序列
// 给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数
// 测试链接 : https://leetcode.cn/problems/distinct-subsequences/

dp[i][j]:s[前i个]子序列能够出现t[前j个]的个数
=dp[i-1][j]
+=dp[i-1][j-1] , s[i-1]==t[j-1]

第0行,0
第0列,1

code1 动态规划
code2 空间压缩

package class068;// 不同的子序列
// 给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数
// 测试链接 : https://leetcode.cn/problems/distinct-subsequences/
public class Code01_DistinctSubsequences {// 已经展示太多次从递归到动态规划了// 直接写动态规划吧public static int numDistinct1(String str, String target) {char[] s = str.toCharArray();char[] t = target.toCharArray();int n = s.length;int m = t.length;// dp[i][j] :// s[前缀长度为i]的所有子序列中,有多少个子序列等于t[前缀长度为j]int[][] dp = new int[n + 1][m + 1];for (int i = 0; i <= n; i++) {dp[i][0] = 1;}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {dp[i][j] = dp[i - 1][j];if (s[i - 1] == t[j - 1]) {dp[i][j] += dp[i - 1][j - 1];}}}return dp[n][m];}// 空间压缩public static int numDistinct2(String str, String target) {char[] s = str.toCharArray();char[] t = target.toCharArray();int n = s.length;int m = t.length;int[] dp = new int[m + 1];dp[0] = 1;for (int i = 1; i <= n; i++) {for (int j = m; j >= 1; j--) {if (s[i - 1] == t[j - 1]) {dp[j] += dp[j - 1];}}}return dp[m];}}

code2 72. 编辑距离

// 编辑距离
// 给你两个单词 word1 和 word2
// 请返回将 word1 转换成 word2 所使用的最少代价
// 你可以对一个单词进行如下三种操作:
// 插入一个字符,代价a
// 删除一个字符,代价b
// 替换一个字符,代价c
// 测试链接 : https://leetcode.cn/problems/edit-distance/

dp[i][j]:word1[前i个]能够转换word2[前j个]
dp[i-1][j-1] , word1[i-1]==word2[j-1]
dp[i][j-1]+a,插入
dp[i-1][j]+b,删除
dp[i-1][j-1]+c,替换word1[i-1]!=word2[j-1]

第0行,插入j个
第0列,删除i个

code1 动态规划
code2 空间压缩

package class068;// 编辑距离
// 给你两个单词 word1 和 word2
// 请返回将 word1 转换成 word2 所使用的最少代价
// 你可以对一个单词进行如下三种操作:
// 插入一个字符,代价a
// 删除一个字符,代价b
// 替换一个字符,代价c
// 测试链接 : https://leetcode.cn/problems/edit-distance/
public class Code02_EditDistance {// 已经展示太多次从递归到动态规划了// 直接写动态规划吧public int minDistance(String word1, String word2) {return editDistance2(word1, word2, 1, 1, 1);}// 原初尝试版// a : str1中插入1个字符的代价// b : str1中删除1个字符的代价// c : str1中改变1个字符的代价// 返回从str1转化成str2的最低代价public static int editDistance1(String str1, String str2, int a, int b, int c) {char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();int n = s1.length;int m = s2.length;// dp[i][j] :// s1[前缀长度为i]想变成s2[前缀长度为j],至少付出多少代价int[][] dp = new int[n + 1][m + 1];for (int i = 1; i <= n; i++) {dp[i][0] = i * b;}for (int j = 1; j <= m; j++) {dp[0][j] = j * a;}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {int p1 = Integer.MAX_VALUE;if (s1[i - 1] == s2[j - 1]) {p1 = dp[i - 1][j - 1];}int p2 = Integer.MAX_VALUE;if (s1[i - 1] != s2[j - 1]) {p2 = dp[i - 1][j - 1] + c;}int p3 = dp[i][j - 1] + a;int p4 = dp[i - 1][j] + b;dp[i][j] = Math.min(Math.min(p1, p2), Math.min(p3, p4));}}return dp[n][m];}// 枚举小优化版// a : str1中插入1个字符的代价// b : str1中删除1个字符的代价// c : str1中改变1个字符的代价// 返回从str1转化成str2的最低代价public static int editDistance2(String str1, String str2, int a, int b, int c) {char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();int n = s1.length;int m = s2.length;// dp[i][j] :// s1[前缀长度为i]想变成s2[前缀长度为j],至少付出多少代价int[][] dp = new int[n + 1][m + 1];for (int i = 1; i <= n; i++) {dp[i][0] = i * b;}for (int j = 1; j <= m; j++) {dp[0][j] = j * a;}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (s1[i - 1] == s2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];} else {dp[i][j] = Math.min(Math.min(dp[i - 1][j] + b, dp[i][j - 1] + a), dp[i - 1][j - 1] + c);}}}return dp[n][m];}// 空间压缩public static int editDistance3(String str1, String str2, int a, int b, int c) {char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();int n = s1.length;int m = s2.length;int[] dp = new int[m + 1];for (int j = 1; j <= m; j++) {dp[j] = j * a;}for (int i = 1, leftUp, backUp; i <= n; i++) {leftUp = (i - 1) * b;dp[0] = i * b;for (int j = 1; j <= m; j++) {backUp = dp[j];if (s1[i - 1] == s2[j - 1]) {dp[j] = leftUp;} else {dp[j] = Math.min(Math.min(dp[j] + b, dp[j - 1] + a), leftUp + c);}leftUp = backUp;}}return dp[m];}}

code3 97. 交错字符串

// 交错字符串
// 给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的
// 测试链接 : https://leetcode.cn/problems/interleaving-string/

前提:s1.length+s2.length==s3.length
dp[i][j]:s1[前i个]和s2[前j个]组成s3[前i+j个]
s1[i-1]==s3[i+j-1]&&dp[i-1][j]
|| s2[j-1]==s3[i+j-1]&&dp[i][j-1]

第0行 s2匹配s3
第0列 s1匹配s3

code1 动态规划
code2 空间压缩

package class068;// 交错字符串
// 给定三个字符串 s1、s2、s3
// 请帮忙验证s3是否由s1和s2交错组成
// 测试链接 : https://leetcode.cn/problems/interleaving-string/
public class Code03_InterleavingString {// 已经展示太多次从递归到动态规划了// 直接写动态规划吧public static boolean isInterleave1(String str1, String str2, String str3) {if (str1.length() + str2.length() != str3.length()) {return false;}char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();char[] s3 = str3.toCharArray();int n = s1.length;int m = s2.length;// dp[i][j]:// s1[前缀长度为i]和s2[前缀长度为j],能否交错组成出s3[前缀长度为i+j]boolean[][] dp = new boolean[n + 1][m + 1];dp[0][0] = true;for (int i = 1; i <= n; i++) {if (s1[i - 1] != s3[i - 1]) {break;}dp[i][0] = true;}for (int j = 1; j <= m; j++) {if (s2[j - 1] != s3[j - 1]) {break;}dp[0][j] = true;}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {dp[i][j] = (s1[i - 1] == s3[i + j - 1] && dp[i - 1][j]) || (s2[j - 1] == s3[i + j - 1] && dp[i][j - 1]);}}return dp[n][m];}// 空间压缩public static boolean isInterleave2(String str1, String str2, String str3) {if (str1.length() + str2.length() != str3.length()) {return false;}char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();char[] s3 = str3.toCharArray();int n = s1.length;int m = s2.length;boolean[] dp = new boolean[m + 1];dp[0] = true;for (int j = 1; j <= m; j++) {if (s2[j - 1] != s3[j - 1]) {break;}dp[j] = true;}for (int i = 1; i <= n; i++) {dp[0] = s1[i - 1] == s3[i - 1] && dp[0];for (int j = 1; j <= m; j++) {dp[j] = (s1[i - 1] == s3[i + j - 1] && dp[j]) || (s2[j - 1] == s3[i + j - 1] && dp[j - 1]);}}return dp[m];}}

code4 有效涂色问题

// 有效涂色问题
// 给定n、m两个参数
// 一共有n个格子,每个格子可以涂上一种颜色,颜色在m种里选
// 当涂满n个格子,并且m种颜色都使用了,叫一种有效方法
// 求一共有多少种有效的涂色方法
// 1 <= n, m <= 5000
// 结果比较大请 % 1000000007 之后返回
// 对数器验证

dp[i][j]:前i个格子有j种颜色的涂法
+=dp[i-1][j] * m

+=dp[i][j-1] * (m-j+1)

第1行:0
第1列: m

package class068;import java.util.Arrays;// 有效涂色问题
// 给定n、m两个参数
// 一共有n个格子,每个格子可以涂上一种颜色,颜色在m种里选
// 当涂满n个格子,并且m种颜色都使用了,叫一种有效方法
// 求一共有多少种有效的涂色方法
// 1 <= n, m <= 5000
// 结果比较大请 % 1000000007 之后返回
// 对数器验证
public class Code04_FillCellsUseAllColorsWays {// 暴力方法// 为了验证public static int ways1(int n, int m) {return f(new int[n], new boolean[m + 1], 0, n, m);}// 把所有填色的方法暴力枚举// 然后一个一个验证是否有效// 这是一个带路径的递归// 无法改成动态规划public static int f(int[] path, boolean[] set, int i, int n, int m) {if (i == n) {Arrays.fill(set, false);int colors = 0;for (int c : path) {if (!set[c]) {set[c] = true;colors++;}}return colors == m ? 1 : 0;} else {int ans = 0;for (int j = 1; j <= m; j++) {path[i] = j;ans += f(path, set, i + 1, n, m);}return ans;}}// 正式方法// 时间复杂度O(n * m)// 已经展示太多次从递归到动态规划了// 直接写动态规划吧// 也不做空间压缩了,因为千篇一律// 有兴趣的同学自己试试public static int MAXN = 5001;public static int[][] dp = new int[MAXN][MAXN];public static int mod = 1000000007;public static int ways2(int n, int m) {// dp[i][j]:// 一共有m种颜色// 前i个格子涂满j种颜色的方法数for (int i = 1; i <= n; i++) {dp[i][1] = m;}for (int i = 2; i <= n; i++) {for (int j = 2; j <= m; j++) {dp[i][j] = (int) (((long) dp[i - 1][j] * j) % mod);dp[i][j] = (int) ((((long) dp[i - 1][j - 1] * (m - j + 1)) + dp[i][j]) % mod);}}return dp[n][m];}public static void main(String[] args) {// 测试的数据量比较小// 那是因为数据量大了,暴力方法过不了// 但是这个数据量足够说明正式方法是正确的int N = 9;int M = 9;System.out.println("功能测试开始");for (int n = 1; n <= N; n++) {for (int m = 1; m <= M; m++) {int ans1 = ways1(n, m);int ans2 = ways2(n, m);if (ans1 != ans2) {System.out.println("出错了!");}}}System.out.println("功能测试结束");System.out.println("性能测试开始");int n = 5000;int m = 4877;System.out.println("n : " + n);System.out.println("m : " + m);long start = System.currentTimeMillis();int ans = ways2(n, m);long end = System.currentTimeMillis();System.out.println("取余之后的结果 : " + ans);System.out.println("运行时间 : " + (end - start) + " 毫秒");System.out.println("性能测试结束");}}

code5 最少删除多少字符可以变成子串

// 最少删除多少字符可以变成子串
// 给定两个字符串s1和s2
// 返回s1至少删除多少字符可以成为s2的子串
// 对数器验证

dp[i][j]:s1[前i个]成为s2[前j个]任意后缀串至少删除字符的个数
dp[i-1][j-1],s1[i-1]==s2[j-1]
dp[i-1][j]+1

第0行:0
第0列:i

返回dp[n][…]中最小的

package class068;import java.util.ArrayList;
import java.util.List;// 删除至少几个字符可以变成另一个字符串的子串
// 给定两个字符串s1和s2
// 返回s1至少删除多少字符可以成为s2的子串
// 对数器验证
public class Code05_MinimumDeleteBecomeSubstring {// 暴力方法// 为了验证public static int minDelete1(String s1, String s2) {List<String> list = new ArrayList<>();f(s1.toCharArray(), 0, "", list);// 排序 : 长度大的子序列先考虑// 因为如果长度大的子序列是s2的子串// 那么需要删掉的字符数量 = s1的长度 - s1子序列长度// 子序列长度越大,需要删掉的字符数量就越少// 所以长度大的子序列先考虑list.sort((a, b) -> b.length() - a.length());for (String str : list) {if (s2.indexOf(str) != -1) {// 检查s2中,是否包含当前的s1子序列strreturn s1.length() - str.length();}}return s1.length();}// 生成s1字符串的所有子序列串public static void f(char[] s1, int i, String path, List<String> list) {if (i == s1.length) {list.add(path);} else {f(s1, i + 1, path, list);f(s1, i + 1, path + s1[i], list);}}// 正式方法,动态规划// 已经展示太多次从递归到动态规划了// 直接写动态规划吧// 也不做空间压缩了,因为千篇一律// 有兴趣的同学自己试试public static int minDelete2(String str1, String str2) {char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();int n = s1.length;int m = s2.length;// dp[len1][len2] :// s1[前缀长度为i]至少删除多少字符,可以变成s2[前缀长度为j]的任意后缀串int[][] dp = new int[n + 1][m + 1];for (int i = 1; i <= n; i++) {dp[i][0] = i;for (int j = 1; j <= m; j++) {if (s1[i - 1] == s2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];} else {dp[i][j] = dp[i - 1][j] + 1;}}}int ans = Integer.MAX_VALUE;for (int j = 0; j <= m; j++) {ans = Math.min(ans, dp[n][j]);}return ans;}// 为了验证// 生成长度为n,有v种字符的随机字符串public static String randomString(int n, int v) {char[] ans = new char[n];for (int i = 0; i < n; i++) {ans[i] = (char) ('a' + (int) (Math.random() * v));}return String.valueOf(ans);}// 为了验证// 对数器public static void main(String[] args) {// 测试的数据量比较小// 那是因为数据量大了,暴力方法过不了// 但是这个数据量足够说明正式方法是正确的int n = 12;int v = 3;int testTime = 20000;System.out.println("测试开始");for (int i = 0; i < testTime; i++) {int len1 = (int) (Math.random() * n) + 1;int len2 = (int) (Math.random() * n) + 1;String s1 = randomString(len1, v);String s2 = randomString(len2, v);int ans1 = minDelete1(s1, s2);int ans2 = minDelete2(s1, s2);if (ans1 != ans2) {System.out.println("出错了!");}}System.out.println("测试结束");}}

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

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

相关文章

Mac如何设置control+space切换上一中输入法

#设置方法# *搜索输入法 系统设置-搜索&#xff1a;输入法&#xff0c;并点击键盘快捷键 *点击输入法&#xff0c;勾选&#xff1a;选择上一个输入法&#xff0c;点击完成。

漂亮的WPF界面 流行的一个界面,向上悬浮的窗口,终于试成功了

目前随便打开个APP&#xff0c;就可以看到一个悬浮的窗口 今天测试一下目前流行的一个界面&#xff0c;向上悬浮的窗口&#xff0c;终于试成功了。看着还不错的。

.net core提示The xx field is required,One or more validation errors occurred

访问接口时缺少model中的参数时&#xff0c;会提示&#xff1a; The xx field is required One or more validation errors occurred原因是.net core webapi默认参数为不可空&#xff0c;因此会验证并报错。 解决方案&#xff1a; 在项目的.csproj中&#xff0c;修改Nullable…

Leetcode—2960.统计已测试设备【简单】

2023每日刷题&#xff08;五十六&#xff09; Leetcode—2960.统计已测试设备 实现代码 int countTestedDevices(int* batteryPercentages, int batteryPercentagesSize) {int cnt 0;int ans 0;for(int i 0; i < batteryPercentagesSize; i) {int t batteryPercentage…

装机必备 | 超赞OCR文本识别小工具 Text Scanner

Text Scanner 是一款功能强大的图片扫描工具软件,该软件利用光学字符识别技术&#xff0c;来将图片上的文字内容&#xff0c;直接转换为可编辑文本&#xff0c;实用性很强。 光学字符识别&#xff08;OCR&#xff09;&#xff1a;Text Scanner for Mac采用了先进的OCR技术&…

qt 使用百度在线地图 方法2

使用百度在线地图两个关键点&#xff0c;一是html页面准备&#xff1b;二是qt 与js 语言的交互。 1&#xff0c;html页面的准备&#xff0c;双击页面就可以出现如下效果。 主要代码&#xff1a; <!DOCTYPE html> <html> <head><meta http-equiv"C…

【Maven技术专题】「入门到精通」教你如何使用Maven中引用依赖本地Jar包,并进行打包输出

前言 在使用Maven管理Java项目时&#xff0c;有时需要引入一些存放在系统特定位置的JAR文件。这些JAR文件可能是你自己编写的&#xff0c;也可能是其他来源的。无论是哪种情况&#xff0c;使用 Maven 的 system 范围和 systemPath 参数&#xff0c;可以方便地引入这些本地依赖…

Logstash输入Kafka输出Es配置

Logstash介绍 Logstash是一个开源的数据收集引擎&#xff0c;具有实时管道功能。它可以从各种数据源中动态地统一和标准化数据&#xff0c;并将其发送到你选择的目的地。Logstash的早期目标主要是用于收集日志&#xff0c;但现在的功能已经远远超出这个范围。任何事件类型都可…

Python从入门到精通九:Python异常、模块与包

了解异常 什么是异常 当检测到一个错误时&#xff0c;Python解释器就无法继续执行了&#xff0c;反而出现了一些错误的提示&#xff0c;这就是所谓的“异常”, 也就是我们常说的BUG bug单词的诞生 早期计算机采用大量继电器工作&#xff0c;马克二型计算机就是这样的。 19…

理解排序算法:冒泡排序、选择排序与归并排序

简介&#xff1a; 在计算机科学中&#xff0c;排序算法是基础且重要的概念。本文将介绍三种常见的排序方法&#xff1a;冒泡排序、选择排序和归并排序。我们将探讨它们的工作原理、特点和适用场景&#xff0c;以帮助读者更好地理解和选择合适的排序方法。 冒泡排序 冒泡排序是…

logback日志框架使用

依赖引入 <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.7</version> </dependency> 使用logback日志框架只需要引入以上即可&#xff0c;(我们平时使用较多的Slf4j…

浏览器提示不安全

当我们使用浏览器访问一个网站时&#xff0c;如果该网站使用的是HTTPS连接&#xff0c;那么浏览器会对其进行安全性的检查。其中一项重要的检查就是确认该网站是否拥有有效的SSL证书。然而&#xff0c;有时我们会在浏览器中看到“不安全”的警告&#xff0c;这通常是由于SSL证书…

三天精通Selenium Web 自动化 - Selenium(Java)环境搭建

1 下载JDK JDK下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2 安装和配置JDK 安装目录尽量不要有空格 D:\Java\jdk1.8.0_91; D:\Java\jre8设置环境变量&#xff1a; “我的电脑”->右键->“属性”->…

C.小苯的排列构造

C-小苯的排列构造_北京信息科技大学第十五届程序设计竞赛&#xff08;同步赛&#xff09; (nowcoder.com) 凑2很容易想出来&#xff0c;但是2 4 1 3 这个内核不好想&#xff0c;算是一种尝试和经验吧 #include<bits/stdc.h> using namespace std;int n;int main() {cin&g…

今天公司来了个拿 30K 出来的测试,算是见识到了基础的天花板

今天上班开早会就是新人见面仪式&#xff0c;听说来了个很厉害的大佬&#xff0c;年纪还不大&#xff0c;是上家公司离职过来的&#xff0c;薪资已经达到中高等水平&#xff0c;很多人都好奇不已&#xff0c;能拿到这个薪资应该人不简单&#xff0c;果然&#xff0c;自我介绍的…

CPU、内存与硬盘及IO操作

目录 1、概念简介 1.1 CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09; 1.2 硬盘&#xff08;Hard Disk Drive&#xff09; 1.3 内存&#xff08;Memory&#xff09; 2、计算机程序在进行io读写操作时&#xff0c;这三者的功能和实现原理 1、概…

【C语言】结构体实现位段

引言 对位段进行介绍&#xff0c;什么是位段&#xff0c;位段如何节省空间&#xff0c;位段的内存分布&#xff0c;位段存在的跨平台问题&#xff0c;及位段的应用。 ✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;…

使用paddleocr识别图片文本的一种方案

pdf文本分为两种&#xff0c;一种是标准的pdf格式的文本&#xff0c;这种无需利用ocr识别&#xff0c;另外一种就是图片文本&#xff0c;这种需要进行ocr的识别。 OCR 识别文本和文本区域 ppstructure是paddleocr里面的一个子库&#xff0c;可以识别文档的页眉页脚、正文、标…

从手工测试进阶中高级测试?如何突破职业瓶颈...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、手工测试如何进…

Linux:gdb的简单使用

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言一、前置理解二、使用总结 前言 gdb是Linux中的调试代码的工具 一、前置理解 我们都知道要调试一份代码&#xff0c;这份代码的发布模式必须是debug。那你知道在li…