动态规划(逐级总结)

注:此篇宏观看待动态规划问题(分步解决问题)

日升时奋斗,日落时自省

目录

1、斐波那契数列模型(爬楼梯)

2、路径问题(地下城)

3、简单多状态问题(买卖股票IV)

4、子数组系列(单词拆分)

5、子序列问题(最长等差数列)

6、回文串问题(回文子串)

 7、两个数组的dp问题(最长重复子数组)

8、01背包问题(分割等和子集)

9、完全背包问题(零钱兑换II)


1、斐波那契数列模型(爬楼梯)

来源力扣:746. 使用最小花费爬楼梯 - 力扣(LeetCode)

 圈了这么几个地方,就是想要到最后一个格子的时候需要的最小花费

状态表示:dp[i]表示第i个位置,最小花费 (题上想要啥满足就是)

状态转移方程:

 初始化(最后两个位置):dp[m-1]=cost[m-1];dp[m-2]=cost[m-2];

前者的数据需要的后者来支持,所以这里初始化后面的数据,我们从后面开始动态规划

填表顺序:

从右往左

返回值:min(dp[0],dp[1])   因为我们可能是从0或者1出发的,所以这里取0或者1最小值

代码:

    public int minCostClimbingStairs(int[] cost) {int m=cost.length;int[] dp=new int[m];dp[m-1]=cost[m-1];dp[m-2]=cost[m-2];for(int i=m-3;i>=0;i--){dp[i]=Math.min(dp[i+1],dp[i+2])+cost[i];}return Math.min(dp[0],dp[1]);}

2、路径问题(地下城)

来源力扣:174. 地下城游戏 - 力扣(LeetCode)

状态分析:

 状态表示(明显是一个二维表):

错误分析:dp[i][j]表示从起点出发,到[i][j]位置的时候,所需血量最小

正确分析:dp[i][j]:表示从[i,j]出发,到终点

初始化:

边界初始化,上图已经给了

 填表顺序:

从下往上,从有往左

返回值:dp[0][0]

代码:

    public int calculateMinimumHP(int[][] dungeon) {int n=dungeon.length;int m=dungeon[0].length;int[][] dp=new int[n+1][m+1];for(int i=0;i<m-1;i++){dp[n][i]=Integer.MAX_VALUE;}for(int j=0;j<n-1;j++){dp[j][m]=Integer.MAX_VALUE;}dp[n-1][m]=1;dp[n][m-1]=1;for(int i=n-1;i>=0;i--){for(int j=m-1;j>=0;j--){dp[i][j]=Math.min(dp[i+1][j],dp[i][j+1])-dungeon[i][j];dp[i][j]=Math.max(1,dp[i][j]);}}return dp[0][0];}

3、简单多状态问题(买卖股票IV)

 来源力扣:188. 买卖股票的最佳时机 IV - 力扣(LeetCode)

状态分析:

f[i][j](表示买入状态):  到第i天 ,完成j次交易 

g[i][j](表示卖出状态):到第i天,完成j次交易

状态转移方程:

状态转移:

f[i][j]=max(f[i-1][j],g[i-1][j]-p[i]); 

由两部分构成

一部分前一天啥也不做还是买入状态就是 i-1,次数还是当前次数j;

另一部分前一天卖出次数仍然没有改变(买入态)i-1,次数还是当前次数j;

g[i][j]=max(f[i-1][j-1]+p[i],g[i-1][j]);

由两部分构成

一部分前一天啥也不做还是卖出状态就是 i-1,次数还是当前次数j;

另一部分前一天买入次数改变状态(卖出态)i-1,次数+1,我们需要的是上一次的j-1;

初始化:

 填表顺序:

从上往下,从左往右

返回值:需要找到最后一行的最大值,相当于是最后一天(没有交易,交易1次....交易n次的结果)

代码:

    public int maxProfit(int k, int[] prices) {int n=prices.length;int[][] f=new int[n][k+1];int[][] g=new int[n][k+1];f[0][0]=-prices[0];g[0][0]=0;//初始化for(int i=1;i<3;i++){f[0][i]=-0x3f3f3f;g[0][i]=-0x3f3f3f;}//状态转义for(int i=1;i<n;i++){for(int j=0;j<k+1;j++){f[i][j]=Math.max(f[i-1][j],g[i-1][j]-prices[i]);g[i][j]=g[i-1][j];if(j-1>=0){g[i][j]=Math.max(g[i][j],f[i-1][j-1]+prices[i]);}}}int ret=0;//从最后一行动规中找最大值for(int i=0;i<k+1;i++){ret=Math.max(ret,g[n-1][i]);}return ret;}

4、子数组系列(单词拆分)

 来源力扣:139. 单词拆分 - 力扣(LeetCode)

状态分析:

状态转义方程:

决定dp[i]的就是两部分是否为 true

dp[j-1]&& substring(j,i+1)

但是为了判断方便这里将单词存到hash表中为了判断截取是否包含单词

初始化:

开始的时候dp[0]就是空串,啥也没有同样为真,因为单词序列中也没有 dp[0]=true

填表顺序:

从左往右

返回值:dp[n]

代码:

    public boolean wordBreak(String s, List<String> wordDict) {/** 优化 将字典里面的单词存到哈希表中* */Set<String> hash=new HashSet<>(wordDict);int n=s.length();boolean[] dp=new boolean[n+1];dp[0]=true;s=" "+s;   //加空串是为了动规 不用去处理下标映射问题for(int i=1;i<=n;i++){//第二次for循环没有方向要求, j=1; j<=i ;j++ 也行for(int j=i;j>=1;j--){if(dp[j-1]&&hash.contains(s.substring(j,i+1))){dp[i]=true;break;}}}return dp[n];}

5、子序列问题(最长等差数列)

注:子序列和子数组是不一样的

子序列是不一定连续的子集,子数组是连续的子集

 来源力扣:1027. 最长等差数列 - 力扣(LeetCode)

状态分析:

动态转义方程:

那这么才能知道k下标的数字是不是在数组中,那就把下标和数字关联起来,来一个哈希关联起来

 dp[i][j]=dp[2b-c][i]+1 

然后记录数据

初始化:等差数列至少需要3个的,基本数量为2,a需要b、c才能确定

填表顺序:从前往后,因为第三个数据需要依赖前两个值才能确定找不找到

返回值:统计的个数

代码:

    public int longestArithSeqLength(int[] nums) {Map<Integer,Integer> hash=new HashMap<>();//首先将第一个值hash.put(nums[0],0);int n=nums.length;int[][] dp=new int[n][n];//进行初始化为 个数2for(int i=0;i<n;i++){Arrays.fill(dp[i],2);}int ret=2; //计算个数为2for(int i=1;i<n;i++){   //相当于 b//第二个值从 b位置开始   j的位置相当于cfor(int j=i+1;j<n;j++){//计算 a 的 2b-cint a=2*nums[i]-nums[j];//此时判断 hash 是否包含 a if(hash.containsKey(a)){dp[i][j]=dp[hash.get(a)][i]+1;//计算次数ret=Math.max(dp[i][j],ret);}}//将本次数字添加到hashhash.put(nums[i],i);}return ret;}

6、回文串问题(回文子串)

 来源力扣:647. 回文子串 - 力扣(LeetCode)

状态分析:

状态转义方程:

根据状态分析写

如果s[i]!=s[j] 说明dp[i][j]==false;这个基本不用写

后面三个条件可以直接合成一个三目运算

如果s[i]==s[j]则 dp[i][j]=i+1<j?dp[i+1][j-1]:true

如果i+1<j 说明不是相邻也不是重叠那就需要区间[i+1,j-1]是true

初始化:不用初始化

填表顺序:其实需要看状态分析 中的dp[i][j]可能会依赖到dp[i+1][j-1]

从下往上,从左往右  i表示行  j表示列

返回值:统计有多少个子串,把dp中为true都计数一下

代码:

    public int countSubstrings(String s) {int n=s.length();//创建后默认为false  为false的情况不用处理boolean[][] dp=new boolean[n][n];int ret=0;for(int i=n-1;i>=0;i--){for(int j=i;j<n;j++){//只需要相等设置为trueif(s.charAt(i)==s.charAt(j)){dp[i][j]=i+1<j?dp[i+1][j-1]:true;}//如果是true说明本身计数if(dp[i][j]==true){ret++;}}}return ret;}

注:为啥第二次for循环从i开始 因为j等于>=i所以j从i开始

 7、两个数组的dp问题(最长重复子数组)

力扣来源:718. 最长重复子数组 - 力扣(LeetCode)

状态分析:

 状态转义方程:

如果两个数组数值相同的话

不等的情况下就不用处理了,相等的话满足动规dp[i][j]=dp[i-1][j-1]+1

初始化:

填表顺序:

从上往下,从左往右

返回值:统计的个数

代码:

    public int findLength(int[] nums1, int[] nums2) {int m=nums1.length;int n=nums2.length;int[][] dp=new int[m+1][n+1];//计数器int ret=0;for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){//如果两个值相等的话if(nums1[i-1]==nums2[j-1]){//相当于个数加一dp[i][j]=dp[i-1][j-1]+1;//求取最大长度ret=Math.max(ret,dp[i][j]);}}}return ret;}

8、01背包问题(分割等和子集)

01背包问题:就是满足于

牛客来源:416. 分割等和子集 - 力扣(LeetCode)

状态分析:

状态转义方程:

初始化:看见 dp[i-1][j-num[i]],需要依赖上一行,所以需要一个扩展行

填表顺序:

从左往右,从上往下

返回值:dp[n][sum/2]

代码:

    public boolean canPartition(int[] nums) {int n=nums.length;int sum=0;//求所有和for(int x:nums)sum+=x;//如果是奇数 就没有相等的情况if(sum%2==1)return false;//求子集的一半int aim=sum/2;//行要多一行  aim 可以不加1 这里只是为了方便理解boolean[][] dp=new boolean[n+1][aim+1];//一行所有的值 为 truefor(int i=0;i<=n;i++){dp[i][0]=true;}for(int i=1;i<=n;i++){//从 i 开始  避开开始的位置for(int j=1;j<=aim;j++){//不选择 第i个位置 dp[i][j]=dp[i-1][j];//选择第i个位置 需要条件的 当前值 大于 数值if(j>=nums[i-1]){//选i 和 不选i 的情况 只要能构成就可以子集一半就行dp[i][j]=dp[i][j]||dp[i-1][j-nums[i-1]];}}}return dp[n][aim];}

 优化:

 代码:

简单点说:直接把行都删了就行  (这里算是优化版的优化,直接让数组从大于nums[i-1]的位置开始的就不用判断j>nums[i-1])

    public boolean canPartition(int[] nums) {int n=nums.length;int sum=0;for(int x:nums)sum+=x;if(sum%2==1)return false;int aim=sum/2;boolean[] dp=new boolean[aim+1];dp[0]=true;for(int i=1;i<=n;i++){for(int j=aim;j>=nums[i-1];j--){dp[j]=dp[j]||dp[j-nums[i-1]];}}return dp[aim];}

9、完全背包问题(零钱兑换II)

力扣来源:518. 零钱兑换 II - 力扣(LeetCode)

状态分析:

 状态转义方程:

但是 能不能选 i 是需要满足条件的  满足条件就是 j-n*coins>=0 就能满足

初始化:

填表顺序:从左往右,从上往下

返回值: dp[n][amount]

代码:

    public int change(int amount, int[] coins) {int n=coins.length;int[][] dp=new int[n+1][amount+1];//设置第一个值 为 1dp[0][0]=1;for(int i=1;i<=n;i++){//从 0 开始 for(int j=0;j<=amount;j++){//不选 idp[i][j]=dp[i-1][j];//选 i 的时候 就需要 j>=coins 才能加上if(j>=coins[i-1]){dp[i][j]+=dp[i][j-coins[i-1]];}}}return dp[n][amount];}

空间优化: 

简单点说,去掉行,填表顺序是从左往右

代码:

    public int change(int amount, int[] coins) {int n=coins.length;int[] dp=new int[amount+1];dp[0]=1;for(int i=1;i<=n;i++){for(int j=coins[i-1];j<=amount;j++){dp[j]+=dp[j-coins[i-1]];}}return dp[amount];}

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

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

相关文章

编程笔记 html5cssjs 051 CSS表格2-2

编程笔记 html5&css&js 051 CSS表格2-2 一、html表格如何按列设置样式&#xff1f;二、练习小结 多数时候是按列设计表格样式的。 一、html表格如何按列设置样式&#xff1f; 在HTML表格中&#xff0c;可以通过CSS来按列设置样式。以下是一个简单的例子&#xff1a; …

零资本创业106个案例

零资本&#xff1a;【10年创业成功经验教你一万如何赚百万】.pdf: https://url99.ctfile.com/f/33882099-1012075073-9ec698?p5496 (访问密码: 5496) 零资本&#xff1a;【14亿人共同话题&#xff0c;现在做什么最赚钱】.pdf: https://url99.ctfile.com/f/33882099-101207536…

《WebKit 技术内幕》之八(3):硬件加速机制

3 其他硬件加速模块 3.1 2D图形的硬件加速机制 其实网页中有很多绘图操作是针对2D图形的&#xff0c;这些操作包括通常的网页绘制&#xff0c;例如绘制边框、文字、图片、填充等&#xff0c;它们都是典型的2D绘图操作。在HTML5中&#xff0c;规范又引入了2D绘图的画布功能&a…

常用设计模式(工厂方法,抽象工厂,责任链,装饰器模式)

前言 有关设计模式的其他常用模式请参考 单例模式的实现 常见的设计模式(模板与方法&#xff0c;观察者模式&#xff0c;策略模式) 工程方法 定义 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 ——《设…

服务端实现微信小游戏登录

1 微信小程序用户登录及其流程 小程序可以通过微信官方提供的登录能力,便能方便的获取微信提供的用户身份标识,达到建立用户体系的作用。 官方文档提供了登录流程时序图,如下: 从上述的登录流程时序图中我们发现,这里总共涉及到三个概念。 第一个是小程序,小程序即我们…

【征服redis15】分布式锁的功能与整体设计方案

目录 1. 分布式锁的概念 2.基于数据库做分布式锁 2.1 基于表主键唯一做分布式锁 2.2 基于表字段版本号做分布式锁 2.3 基于数据库排他锁做分布式锁 3.使用Redis做分布式锁 3.1 redis实现分布式锁的基本原理 3.2 问题一&#xff1a;增加超时机制&#xff0c;防止长期持有…

【Python从入门到进阶】47、Scrapy Shell的了解与应用

接上篇《46、58同城Scrapy项目案例介绍》 上一篇我们学习了58同城的Scrapy项目案例&#xff0c;并结合实际再次了项目结构以及代码逻辑的用法。本篇我们来学习Scrapy的一个终端命令行工具Scrapy Shell&#xff0c;并了解它是如何帮助我们更好的调试爬虫程序的。 一、Scrapy Sh…

安装python版opencv的一些问题

安装python版opencv的一些问题 OpenCV是知名的开源计算机视觉算法库&#xff0c;提供了C\Python\Java版共享库。 在Python中使用OpenCV格外简单&#xff0c;一句命令就能安装&#xff0c;一行import就能引入&#xff0c;可谓是神器。然而&#xff0c;在实际使用中可能遇到一些…

Java实现大学计算机课程管理平台 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 实验课程档案模块2.2 实验资源模块2.3 学生实验模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 实验课程档案表3.2.2 实验资源表3.2.3 学生实验表 四、系统展示五、核心代码5.1 一键生成实验5.2 提交实验5.3 批阅实…

第一篇【传奇开心果系列】beeware的toga开发移动应用:轮盘抽奖移动应用

系列博文目录 beeware的toga开发移动应用示例系列博文目录一、项目目标二、开发传奇开心果轮盘抽奖安卓应用编程思路三、传奇开心果轮盘抽奖安卓应用示例代码四、补充抽奖逻辑实现五、开发传奇开心果轮盘抽奖苹果手机应用编程思路六、开发传奇开心果轮盘抽奖苹果手机应用示例代…

【 CSS 】基础 2

“生活就像骑自行车&#xff0c;想要保持平衡&#xff0c;就得不断前行。” - 阿尔伯特爱因斯坦 CSS 基础 2 1. emmet 语法 1.1 简介 Emmet语法的前身是 Zen coding&#xff0c;它使用缩写&#xff0c;来提高 HTML / CSS 的编写速度&#xff0c; VSCode 内部已经集成该语法。…

Python的50个常识问题解答

一、说明 关于python的一些大致理解&#xff0c;初学者可以参考本文做一个直观理解&#xff1b;其中也不乏有趣事实。 二、python大世界 Python于1991年首次发布&#xff0c;由Guido van Rossum创建。 “python”这个名字来源于英国喜剧团体Monty Python&#xff0c;而不是蛇。…

webpack-dev-server原理解析及其中跨域解决方法

webpack proxy ,就是 webpack 提供的解决跨域的方案。其基本行为是接受客户端发送的请求后转发给其他的服务器&#xff0c;目的是为了解决在开发模式下的跨域问题。 原理 webpack中的proxy 工作原理是利用了 http-proxy-middleware 这个http 代理中间件&#xff0c;实现将请求…

专门为机器学习开发的jpy语言

这本来是一个为工科教学专门开发的附属品&#xff0c;并不是说Python或Java有多不好&#xff0c;根本上它就是一个Java工程教材&#xff0c;但又要结合人工智能。因此&#xff0c;出现了这样一个包容性的怪胎&#xff0c;可以用python一样的语法与Java一起编写。 没流行起来的一…

【ARM 嵌入式 编译系列 2.5 -- GCC 编译参数学习 --specs=nano.specs选项 】

请阅读【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 文章目录 概述nano.specs示例使用注意事项问题总结概述 ARM 工具链 (arm-none-eabi-) 包括了一个叫作 --specs 的编译器和链接器选项,这个选项允许用户指定一个或多个 “specs” 文件,以影响编译或链接阶段的行为。Sp…

<信息安全>《2 国内主要企业网络安全公司概览(二)》

4 北京天融信科技有限公司(简称天融信) 信息内容LOGO成立日期创始于1995年总部北京市海淀区上地东路1号院3号楼北侧301室背景民营企业是否上市天融信[002212]A股市值99亿主要产品网络安全大数据云服务员工规模6000多人简介天融信科技集团&#xff08;证券代码&#xff1a;0022…

【开源】基于JAVA的停车场收费系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 停车位模块2.2 车辆模块2.3 停车收费模块2.4 IC卡模块2.5 IC卡挂失模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 停车场表3.2.2 车辆表3.2.3 停车收费表3.2.4 IC 卡表3.2.5 IC 卡挂失表 四、系统实现五、核心代码…

**PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**

PyTorch月学习计划 - 第6-7天: 自动梯度&#xff08;Autograd&#xff09; 学习目标&#xff1a; 掌握自动微分的基本原理&#xff0c;特别是在深度学习中的应用。 学会如何在PyTorch中使用autograd模块进行自动梯度计算。 学习内容&#xff1a; 自动微分和计算图的概念 自动微…

在达沃斯,人工智能引发的乐观情绪可谓一分为二

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

基于STM32的基础实验(一)

LED实验 采用STM32单片机设计电路&#xff0c;控制LED灯的亮灭&#xff0c;对单片机端口的位操作进行演示。 实验需要&#xff1a; STM32核心板独立LED 电路原理图 LED灯实际上是一个特殊的二极管&#xff0c;通过控制高低电平亮灭。如图所示&#xff0c;当1为低电平&#…