算法体系-20 第二十节暴力递归到动态规划

前言 动态规划模型从尝试暴力递归到傻缓存到动态规划

四种模型和体系班两种模型一共六种模型

0.1 从左往右模型

0.2 范围讨论模型范围尝试模型 (这种模型特别在乎讨论开头如何如何 结尾如何如何)

玩家博弈问题,玩家玩纸牌只能那左或者右

0.3 样本对应样本对应模型(特别在乎两个样本结尾如何如何 最长公共子序列)

0.4 业务限制模型

动态规划只是暴力尝试的一个缓存
 

一 背包问题

1.1 描述

给定两个长度都为N的数组weights和values,

weights[i]和values[i]分别代表 i号物品的重量和价值。

给定一个正数bag,表示一个载重bag的袋子,

你装的物品不能超过这个重量。

返回你能装下最多的价值是多少?

1.2 分析

到当前货物的时候有两种选择,要么选择当前货物,要么不选择当前货物

base 条件的判断分析

if (rest < 0) {

return -1;}

这里为什么不能取return 0,因为上由传下来的剩下的bags的重量要大于0上由的值才是有意义的;

递归改动态规划

第一步找确定的值

if (index == w.length) {

return 0;

}

第二步找动态的值喝确定值之间的关系,动态的值时如何根据静态值退出来的

int p1 = process(w, v, index + 1, rest);

int next = process(w, v, index + 1, rest - w[index]);

这辆动态函数都需要依赖他的一行,最后一行又是确定值

1.3 尝试递归代码

// 所有的货,重量和价值,都在w和v数组里// 为了方便,其中没有负数// bag背包容量,不能超过这个载重// 返回:不超重的情况下,能够得到的最大价值public static int maxValue(int[] w, int[] v, int bag) {if (w == null || v == null || w.length != v.length || w.length == 0) {return 0;}// 尝试函数!return process(w, v, 0, bag);}// index 0~N// rest 负~bagpublic static int process(int[] w, int[] v, int index, int rest) {if (rest < 0) {return -1;}if (index == w.length) {return 0;}//不选择当前的货物int p1 = process(w, v, index + 1, rest);int p2 = 0;//要选择当前的货物int next = process(w, v, index + 1, rest - w[index]);if (next != -1) {p2 = v[index] + next;}return Math.max(p1, p2);}

1.4 改动态规划

递归改动态规划

第一步找确定的值

第二步找动态的值喝确定值之间的关系,动态的值时如何根据静态值退出来的

改动态规划 看是否有重复的情况

下面的p(3,10)都会重复

1.5 动态规划代码

public static int dp(int[] w, int[] v, int bag) {if (w == null || v == null || w.length != v.length || w.length == 0) {return 0;}int N = w.length;int[][] dp = new int[N + 1][bag + 1];for (int index = N - 1; index >= 0; index--) {for (int rest = 0; rest <= bag; rest++) {int p1 = dp[index + 1][rest];int p2 = 0;int next = rest - w[index] < 0 ? -1 : dp[index + 1][rest - w[index]];if (next != -1) {p2 = v[index] + next;}dp[index][rest] = Math.max(p1, p2);}}return dp[0][bag];}public static void main(String[] args) {int[] weights = { 3, 2, 4, 7, 3, 1, 7 };int[] values = { 5, 6, 3, 19, 12, 4, 2 };int bag = 15;System.out.println(maxValue(weights, values, bag));System.out.println(dp(weights, values, bag));}}

二 字符对应数字对应的转换

2.1 描述

规定1和A对应、2和B对应、3和C对应...26和Z对应

那么一个数字字符串比如"111”就可以转化为:

"AAA"、"KA"和"AK"

给定一个只有数字字符组成的字符串str,返回有多少种转化结果

2.2 分析

第一步 到最后一个位置的时候前面做的决定共同构成收获了一个有效的点数

第二步 当前位置是0的是说明前面的做的决定策略错了,0是无效的转化,0没有对应的i字符

第三步 i位置不为0的时候说明该位置可以单转然后轮到 i+1位置去转

第四步 i和i+1位置共同决定,注意越界

2.3 代码

2.3.1尝试递归

    // str只含有数字字符0~9// 返回多少种转化方案public static int number(String str) {if (str == null || str.length() == 0) {return 0;}return process(str.toCharArray(), 0);}// str[0..i-1]转化无需过问// str[i.....]去转化,返回有多少种转化方法public static int process(char[] str, int i) {if (i == str.length) {return 1;}// i没到最后,说明有字符if (str[i] == '0') { // 之前的决定有问题return 0;}// str[i] != '0'// 可能性一,i单转int ways = process(str, i + 1);if (i + 1 < str.length && (str[i] - '0') * 10 + str[i + 1] - '0' < 27) {//可能性二 i和i+1组合成算一种    ways += process(str, i + 2);}return ways;}

2.3.2 递归改动态规划

1.找到base条件

2.根据base条件推出其他情况

为什么取的是dp[0] 是因为递归尝试是从0开始的,递归最终往上返回的0

// 从右往左的动态规划// 就是上面方法的动态规划版本// dp[i]表示:str[i...]有多少种转化方式public static int dp1(String s) {if (s == null || s.length() == 0) {return 0;}char[] str = s.toCharArray();int N = str.length;int[] dp = new int[N + 1];dp[N] = 1;for (int i = N - 1; i >= 0; i--) {if (str[i] != '0') {int ways = dp[i + 1];if (i + 1 < str.length && (str[i] - '0') * 10 + str[i + 1] - '0' < 27) {ways += dp[i + 2];}dp[i] = ways;}}return dp[0];}

三 给定一个字符串str,给定一个字符串类型的数组arr,出现的字符都是小写英文

3.1 描述

给定一个字符串str,给定一个字符串类型的数组arr,出现的字符都是小写英文

arr每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来

返回需要至少多少张贴纸可以完成这个任务。

例子:str= "babac",arr = {"ba","c","abcd"}

ba + ba + c 3 abcd + abcd 2 abcd+ba 2

所以返回2 张贴纸

3.2 分析

就把每一张贴纸作为第一张,有几张贴纸我就给你试多少种情况,答案必在其中,因为肯定有一张贴纸作为了第一张,我就试每一个第一张是哈,我把所有可能第一张都试了,后续最少张数你告诉我,所有分支中最少的那就是我要的

为什么排序?为了命中率高一点,不排序也可以

3.3 代码

public class Code03_StickersToSpellWord {public static int minStickers1(String[] stickers, String target) {int ans = process1(stickers, target);return ans == Integer.MAX_VALUE ? -1 : ans;}// 所有贴纸stickers,每一种贴纸都有无穷张// target// 最少张数public static int process1(String[] stickers, String target) {if (target.length() == 0) {return 0;//这里第一步返回}int min = Integer.MAX_VALUE;for (String first : stickers) {//假如贴纸stickers里面有5个,将这五个都作为第一个去试减去之后看target里面还剩多少target需要拼接的String rest = minus(target, first);//假如第一轮target里面试完了还有target需要再去贴的话进行下一轮if (rest.length() != target.length()) {//进行第一次后的下轮贴纸尝试//这里第一步返回到这里min = Math.min(min, process1(stickers, rest));}}//要将第一次的加进来,每次递归process1没有走到上面的判断都会走到这里返回1或者Integer.MAX_VALUEreturn min + (min == Integer.MAX_VALUE ? 0 : 1);}
public static String minus(String s1, String s2) {char[] str1 = s1.toCharArray();char[] str2 = s2.toCharArray();int[] count = new int[26];for (char cha : str1) {count[cha - 'a']++;}for (char cha : str2) {count[cha - 'a']--;}StringBuilder builder = new StringBuilder();for (int i = 0; i < 26; i++) {if (count[i] > 0) {for (int j = 0; j < count[i]; j++) {builder.append((char) (i + 'a'));}}}return builder.toString();}

3.4 改进 高效做法 优化

四 列子 两个字符串的最长公共子序列 使用的模型的是 (样本对应模型)

4.1 描述

给定两个字符串str1和str2,

返回这两个字符串的最长公共子序列长度

比如 : str1 = “a12b3c456d”,str2 = “1ef23ghi4j56k”

最长公共子序列是“123456”,所以返回长度6

4.2 分析 样本对应模型的经验是从最后一个开始对应

样本对应模型,他往往讨论结尾该如何组织可能性(经验)

4.3 最长公共子序列改动态规划分析

4.4代码

public class Code04_LongestCommonSubsequence {public static int longestCommonSubsequence1(String s1, String s2) {if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {return 0;}char[] str1 = s1.toCharArray();char[] str2 = s2.toCharArray();// 尝试return process1(str1, str2, str1.length - 1, str2.length - 1);}// str1[0...i]和str2[0...j],这个范围上最长公共子序列长度是多少?// 可能性分类:// a) 最长公共子序列,一定不以str1[i]字符结尾、也一定不以str2[j]字符结尾// b) 最长公共子序列,可能以str1[i]字符结尾、但是一定不以str2[j]字符结尾// c) 最长公共子序列,一定不以str1[i]字符结尾、但是可能以str2[j]字符结尾// d) 最长公共子序列,必须以str1[i]字符结尾、也必须以str2[j]字符结尾// 注意:a)、b)、c)、d)并不是完全互斥的,他们可能会有重叠的情况// 但是可以肯定,答案不会超过这四种可能性的范围// 那么我们分别来看一下,这几种可能性怎么调用后续的递归。// a) 最长公共子序列,一定不以str1[i]字符结尾、也一定不以str2[j]字符结尾//    如果是这种情况,那么有没有str1[i]和str2[j]就根本不重要了,因为这两个字符一定没用啊//    所以砍掉这两个字符,最长公共子序列 = str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归)// b) 最长公共子序列,可能以str1[i]字符结尾、但是一定不以str2[j]字符结尾//    如果是这种情况,那么我们可以确定str2[j]一定没有用,要砍掉;但是str1[i]可能有用,所以要保留//    所以,最长公共子序列 = str1[0...i]与str2[0...j-1]的最长公共子序列长度(后续递归)// c) 最长公共子序列,一定不以str1[i]字符结尾、但是可能以str2[j]字符结尾//    跟上面分析过程类似,最长公共子序列 = str1[0...i-1]与str2[0...j]的最长公共子序列长度(后续递归)// d) 最长公共子序列,必须以str1[i]字符结尾、也必须以str2[j]字符结尾//    同时可以看到,可能性d)存在的条件,一定是在str1[i] == str2[j]的情况下,才成立的//    所以,最长公共子序列总长度 = str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归) + 1(共同的结尾)// 综上,四种情况已经穷尽了所有可能性。四种情况中取最大即可// 其中b)、c)一定参与最大值的比较,// 当str1[i] == str2[j]时,a)一定比d)小,所以d)参与// 当str1[i] != str2[j]时,d)压根不存在,所以a)参与// 但是再次注意了!// a)是:str1[0...i-1]与str2[0...j-1]的最长公共子序列长度// b)是:str1[0...i]与str2[0...j-1]的最长公共子序列长度// c)是:str1[0...i-1]与str2[0...j]的最长公共子序列长度// a)中str1的范围 < b)中str1的范围,a)中str2的范围 == b)中str2的范围// 所以a)不用求也知道,它比不过b)啊,因为有一个样本的范围比b)小啊!// a)中str1的范围 == c)中str1的范围,a)中str2的范围 < c)中str2的范围// 所以a)不用求也知道,它比不过c)啊,因为有一个样本的范围比c)小啊!// 至此,可以知道,a)就是个垃圾,有它没它,都不影响最大值的决策// 所以,当str1[i] == str2[j]时,b)、c)、d)中选出最大值// 当str1[i] != str2[j]时,b)、c)中选出最大值public static int process1(char[] str1, char[] str2, int i, int j) {if (i == 0 && j == 0) {// str1[0..0]和str2[0..0],都只剩一个字符了// 那如果字符相等,公共子序列长度就是1,不相等就是0// 这显而易见return str1[i] == str2[j] ? 1 : 0;} else if (i == 0) {// 这里的情况为:// str1[0...0]和str2[0...j],str1只剩1个字符了,但是str2不只一个字符// 因为str1只剩一个字符了,所以str1[0...0]和str2[0...j]公共子序列最多长度为1// 如果str1[0] == str2[j],那么此时相等已经找到了!公共子序列长度就是1,也不可能更大了// 如果str1[0] != str2[j],只是此时不相等而已,// 那么str2[0...j-1]上有没有字符等于str1[0]呢?不知道,所以递归继续找if (str1[i] == str2[j]) {return 1;} else {return process1(str1, str2, i, j - 1);}} else if (j == 0) {// 和上面的else if同理// str1[0...i]和str2[0...0],str2只剩1个字符了,但是str1不只一个字符// 因为str2只剩一个字符了,所以str1[0...i]和str2[0...0]公共子序列最多长度为1// 如果str1[i] == str2[0],那么此时相等已经找到了!公共子序列长度就是1,也不可能更大了// 如果str1[i] != str2[0],只是此时不相等而已,// 那么str1[0...i-1]上有没有字符等于str2[0]呢?不知道,所以递归继续找if (str1[i] == str2[j]) {return 1;} else {return process1(str1, str2, i - 1, j);}} else { // i != 0 && j != 0// 这里的情况为:// str1[0...i]和str2[0...i],str1和str2都不只一个字符// 看函数开始之前的注释部分// p1就是可能性c)  完全不考虑i 所以减去1,可能考虑jint p1 = process1(str1, str2, i - 1, j);// p2就是可能性b) 完全不考虑j 所以减去1,可能考虑iint p2 = process1(str1, str2, i, j - 1);// p3就是可能性d),如果可能性d)存在,即str1[i] == str2[j],那么p3就求出来,参与pk// 如果可能性d)不存在,即str1[i] != str2[j],那么让p3等于0,然后去参与pk,反正不影响int p3 = str1[i] == str2[j] ? (1 + process1(str1, str2, i - 1, j - 1)) : 0;return Math.max(p1, Math.max(p2, p3));}}//转化动态规划public static int longestCommonSubsequence2(String s1, String s2) {if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {return 0;}char[] str1 = s1.toCharArray();char[] str2 = s2.toCharArray();int N = str1.length;int M = str2.length;int[][] dp = new int[N][M];dp[0][0] = str1[0] == str2[0] ? 1 : 0;for (int j = 1; j < M; j++) {dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1];}for (int i = 1; i < N; i++) {dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];}for (int i = 1; i < N; i++) {for (int j = 1; j < M; j++) {int p1 = dp[i - 1][j];int p2 = dp[i][j - 1];int p3 = str1[i] == str2[j] ? (1 + dp[i - 1][j - 1]) : 0;dp[i][j] = Math.max(p1, Math.max(p2, p3));}}return dp[N - 1][M - 1];}}

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

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

相关文章

【DrissionPage】Linux上如何将https改为http

最近有个老板找我做一个自动化的程序&#xff0c;要求部署到Linux上 这是一个http协议的网站&#xff0c;chrome在默认设置下&#xff0c;会将http的网站识别成不安全的内容&#xff0c;然后自动将http转化成https访问 但是&#xff0c;这个http的网站它的加载项里既有http的…

HAL库--内存保护(MPU)实验

MPU是内核外设&#xff0c;想获取相关资料只能从内核手册查找 MPU功能仅F7/H7系列具备 内存保护单元(MPU介绍) MPU基本介绍 说白了MPU用来管理内存和外设存储区的访问权限 MPU可配置保护8/16个内存区域(看芯片型号)&#xff0c;每个区域最小要求256字节&#xff0c;且每个区…

STL入门指南:从容器到算法的完美结合

目录 ​编辑 一、什么是STL 二、STL的版本 三、STL的六大组件 1. 容器&#xff08;Containers&#xff09;&#xff1a; 2. 算法&#xff08;Algorithms&#xff09;&#xff1a; 3. 迭代器&#xff08;Iterators&#xff09;&#xff1a; 4. 仿函数&#xff08;Functo…

安鸾学院靶场——安全基础

文章目录 1、Burp抓包2、指纹识别3、压缩包解密4、Nginx整数溢出漏洞5、PHP代码基础6、linux基础命令7、Mysql数据库基础8、目录扫描9、端口扫描10、docker容器基础11、文件类型 1、Burp抓包 抓取http://47.100.220.113:8007/的返回包&#xff0c;可以拿到包含flag的txt文件。…

天降流量于雀巢?元老品牌如何创新营销策略焕新生

大家最近有看到“南京阿姨手冲咖啡”的视频吗&#xff1f;三条雀巢速溶咖啡入杯&#xff0c;当面加水手冲&#xff0c;十元一份售出&#xff0c;如此朴实的售卖方式迅速在网络上走红。而面对这一波天降的热度&#xff0c;雀巢咖啡迅速做出了回应&#xff0c;品牌组特地去到了阿…

计算机SCI期刊,中科院3区,IF=5.6,审稿速度非常快

一、期刊名称 International Journal of Machine Learning and Cybernetics 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机科学 影响因子&#xff1a;5.6 中科院分区&#xff1a;3区 三、期刊征稿范围 控制论关注的是描述我们日常生活中无处不在…

迅狐跨境商城系统|全平台兼容|前端采用uni-app跨端框架,后端采用ThinkPHP5框架

高效实现全平台兼容的迅狐跨境商城系统 迅狐跨境商城系统是一款专为跨境电商企业设计的全平台兼容系统。其前端采用uni-app跨端框架&#xff0c;后端采用ThinkPHP5框架&#xff0c;旨在实现高效的开发和运营管理。 1. 全平台兼容的前端设计 迅狐跨境商城系统的前端采用uni-a…

STM32开发过程中碰到的问题总结 - 1

文章目录 前言1. 怎么生成keil下可以使用的文件和gcc下编译使用的makefile2. STM32的时钟树3.怎么查看keil5下的编译工具链用的是哪个4. Arm编译工具链和GCC编译工具链有什么区别吗&#xff1f;5. 怎么查看Linux虚拟机是x86的还是aarch646. 怎么下载gcc-arm的编译工具链7.怎么修…

PlugLink:让数据分析与工作流无缝连接(附源码)

PlugLink&#xff1a;让数据分析与工作流无缝连接 引言 数据分析和自动化工作流已成为各个企业和个人提高效率的关键手段。今天&#xff0c;我要介绍一款名为PlugLink的工具&#xff0c;它不仅能帮助你轻松进行数据分析&#xff0c;还能将这些分析结果无缝连接到你的工作流中&…

基于 Python 解析 XML 文件并将数据存储到 MongoDB 数据库

1. 问题背景 在软件开发中&#xff0c;我们经常需要处理各种格式的数据。XML 是一种常用的数据交换格式&#xff0c;它可以存储和传输结构化数据。很多网站会提供 XML 格式的数据接口&#xff0c;以便其他系统可以方便地获取数据。 我们有这样一个需求&#xff1a;我们需要从…

Vue30-自定义指令:对象式

一、需求&#xff1a;创建fbind指定 要用js代码实现自动获取焦点的功能&#xff01; 二、实现 2-1、步骤一&#xff1a;绑定元素 2-2、步骤二&#xff1a;input元素获取焦点 此时&#xff0c;页面初始化的时候&#xff0c;input元素并没有获取焦点&#xff0c;点击按钮&…

NestJS学习笔记

一、安装NestJS CLI工具 环境检查 //查看node版本 node -v//查看npm版本 npm -v 安装nest/cli 使用npm全局安装nestjs/cli npm i -g nestjs/cli 查看nest版本 nest -v 结果如图&#xff1a; 创建nest项目 //命令行创建nest项目 nest new 【项目名】 VScode扩展下载 1、…

远程登录新建会话

在做远程登录会话建立的时候有时候会忘记顺便就记录了&#xff0c;方便后期回顾

没有登录微信就不会截图了?这个方法你一定要学会

前言 前段时间小白在指导小伙伴的时候&#xff0c;发现他在电脑没有登录微信的时候就不会截图了。 这个可就难倒他了…… 所以他登录了个微信&#xff0c;然后截了张图&#xff0c;接着把微信退出了。这人可真是谨慎啊&#xff5e; 所以&#xff0c;小伙伴在使用电脑的时候…

JWT工具【工具类】

一、JWT JSON Web Token (JWT)是一个开放标准&#xff08;RFC 7519&#xff09;&#xff0c;定义了一种紧凑且自包含的方式&#xff0c;以JSON对象的形式在各方之间安全地传输信息。这种信息可以被验证和信任&#xff0c;因为它是数字签名的。具体来说&#xff0c;JWT是一种用…

科技赋能,避震婴儿车或成为行业硬通货

全球知识经济发展发展到今天&#xff0c;消费者对于品质、服务、体验的要求越来越高&#xff0c;与之对应的产品也就越来越科技化、智能化、个性化&#xff0c;品牌化和差异化逐步成为产品的竞争核心。 婴儿推车作为关系婴幼儿出行安全的支柱性产业之一&#xff0c;从车架结构…

graalvm编译springboot3 native应用

云原生时代容器先行&#xff0c;为了更好的拥抱云原生&#xff0c;spring boot3之后&#xff0c;推出了graalvm编译boot项目&#xff0c;利用jvm的AOT&#xff08; Ahead Of Time &#xff09;运行前编译技术&#xff0c;可以将javay源码直接构建成机器码二进制的文件&#xff…

泰坦尼克号数据集机器学习实战教程

泰坦尼克号数据集是一个公开可获取的数据集&#xff0c;源自1912年沉没的RMS泰坦尼克号事件。这个数据集被广泛用于教育和研究&#xff0c;特别是作为机器学习和数据分析的经典案例。数据集记录了船上乘客的一些信息&#xff0c;以及他们是否在灾难中幸存下来。以下是数据集中主…

嵌入式实训day3

1、 planet_list["水星","金星","火星","木星"] print(planet_list)planet_list.insert(2,"地球") print(planet_list)planet_list.append("土星") planet_list.append("天王星") planet_list.append(&…

MultiTrust:首个综合统一的多模态信任度基准(上)

随着我们迈向人工通用智能&#xff08;AGI&#xff09;的时代&#xff0c;出现了开创性的大语言模型&#xff08;LLMs&#xff09;。凭借它们强大的语言理解和推理能力&#xff0c;已经无缝地将其他模态&#xff08;例如视觉&#xff09;整合到LLMs中&#xff0c;以理解不同的输…