java算法day27

java算法day27

  • 动态规划初步总结
  • 509 斐波那契数
  • 杨辉三角
  • 打家劫舍
  • 完全平方数

动态规划初步总结

如果你感觉某个问题有很多重叠子问题,使用动态规划是最有效的。
动态规划的过程就是每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心了。贪心是“直接”从局部选最优的。

看到目前的各种教程,目前能看懂的动态规划思想总结就是:
这三步:
1、穷举法(暴力搜索)
2、记忆化搜索(剪枝)
3、改写成迭代形式。

目前我只能一步步的做题来体会动态规划。


509 斐波那契数列

目前就拿着上面总结的思想来做做题。

拿到这个题,我上来就想到了递归解法(这也对应着上面的第一点)。然后快速就交了,过了,但是超越百分之5。足以见得效率非常的低。

class Solution {public int fib(int n) {if(n == 0){return 0;}if(n == 1){return 1;}return fib(n-2) + fib(n-1);}
}

问题出在哪里,从递归树里就清楚了
在这里插入图片描述
从这个计算过程可以看到,存在着大量的重复计算。比如计算f(18)和f(19)的时候,都会计算f(17),而计算f(17)的过程又需要往下递归,意思说f(17)要算两次。往下那肯定存在更多的重复性计算。所以说这是需要优化的点。

如何优化,如何实现快速访问,这里我们可以想到哈希,下次我要计算之前,我先不着急递归,我先去hash里面看看有没有现成的,直接哪来用。那么按照这样的想法我们就可以创建一个哈希表,至于这个表是什么样的,可以根据题目来。

有时候可能还想不通,那这个hash里面的值是怎么记录下来的,那我只能说要把递归的过程想清楚。
通过上面的代码,算f(5) return f(4) + f(3) 。那么按程序执行顺序来说,肯定是先进f(4),然后一直往下走
比如f(4) return f(3) + f(2)
f(3) = f(2) + f(1)
然后f(2) = f(1)+f(0) 。可以见得,在不断下去的过程中,f(4),f(3),f(2),f(1),f(0)都会计算。所以说在这最左边的分支,其实就已经把别的分支那些重复的点全计算完了。所以hash就是在这里就完成了计算,怎么算?这个过程中程序要进行计算,hash表直接把这个结果也存到自己的哈希表里不就完事了。

从这个过程,再对上面的递归树做一个优化,你可以看到这样的变化。
在这里插入图片描述
是不是感觉2^n级别的复杂度立马变o(n)了。
在这里插入图片描述
带备忘录的写法如下:

class Solution {public int fib(int n) {if(n<1){return 0;}int[] memo = new int[31];return helper(n,memo);}int helper(int n,int[] memo){if(n == 1 || n == 2){return 1;}if(memo[n]!=0){return memo[n];}memo[n] = helper(n-1,memo)+helper(n-2,memo);return memo[n];}}

这么这就是dp了吗?还不是!
这其实还是一个自顶向下的解法。

真正的dp是什么。真正的dp是自底向上,从最小的子问题开始,然后逐步构造最大的解,直到达到目标。

动态规划的本质:动态规划的核心是通过解决子问题来解决更大的问题,在斐波那契数的例子中,我们直到每个数都是前两个数的和。

所以这里可以总结出动态规划问题的真正含义了。
我先来说说动态规划是如何解决这个问题的,首先如果清楚子问题是什么样的,然后清楚子问题的初状态,那么我就能够直接从这个子问题出发,不断地进行状态运算,直到状态转移到最终结果。然后这个得到下一个状态的方法,就是所谓的状态转移方程。

所以这里可以总结一个结论:
也就是很多教程里面教的方法:
子问题的识别
正如你所说,清楚地识别子问题是关键。在斐波那契数列中,子问题就是计算每个 F(i)。

初始状态(基本情况)
这些是已知的最小子问题的解。在斐波那契数列中,F(0) = 0 和 F(1) = 1。

状态转移
这是从一个子问题到另一个子问题的过程。在斐波那契数列中,状态转移方程是 F(i) = F(i-1) + F(i-2)。

最终状态
这是我们最终要求解的问题。在斐波那契数列中,就是计算 F(n)。

从初始状态到最终状态
正如你所说,我们可以从初始状态开始,通过不断应用状态转移方程,最终达到我们想要的结果。

说的更直白一点:
也就是说,如果我在做题的过程中,搞清楚了什么是子问题,还有初始状态,知道下一个状态该如何正确计算。那么我就能从这个初始状态直接往后推,直到推出最后的正确答案。


然后就立马写出了这个题。感觉还是非常清楚的。
子问题怎么找? 这里我看网上一般是通过推广的办法,由f(n)来思考那么是要计算f(n-1)+f(n-2)。那么推广到i就是dp[i] = dp[i-1]+dp[i-2];所以子问题就是计算dp[i-1]和dp[i-2]。往最初的状态倒就是从dp[0] 和 dp[1]开始
状态转移方程是啥? 就是怎么计算下一个状态,这里状态转移方程就是dp[i] = dp[i-1]+dp[i-2]
最终状态怎么确定? 就是看dp要到哪停下来。这里就是算dp[n]

dp数组到底怎么初始化?这个我认为一是要根据问题,而是要根据数据的边界。即最大可能取到的状态来确定长度。

class Solution {public int fib(int n) {//快速特判if(n<2){return n;}int[] dp = new int[n+1];dp[0] = 0;dp[1] = 1;for(int i = 2;i<=n;i++){dp[i] = dp[i-1]+dp[i-2];}return dp[n];}
}

提交之后会发现,效率和备忘录那个写法的效率相同
因为这俩的计算纯粹是反过来的关系

然后还可以再进一步优化

是不是发现我们其实只要这个最后的dp[n],甚至感觉这个dp数组有点多余了。
确实是,我们其实就只需要不断的迭代更新后面两个数字 即 dp[i-1] 和 dp[i-2]
这个技巧就是所谓的状态压缩 空间复杂度直接优化为o1了。
怎么理解状态压缩的应用?就是想想原来的dp数组,有没有一些空间是不必要存储的。

所以这里还有一个究极版本。

class Solution {public int fib(int n) {if(n<2){return n;}int pre = 0;int cur = 1;for(int i = 2;i<=n;i++){//sum是下一个状态int sum = pre+cur;pre = cur;cur = sum;}return cur;}
}

零钱兑换

上面的斐波那契还体现不出dp。因为没有求最值问题,现在来看看这个题。
我第一想法就是一个大回溯直接爆搜。果不其然第32个例子直接超时。

接下来就只能看看题解了,用dp来做这个题。

这里得到第一个知识点:能用dp,首先要复合最优子结构,子问题间必须互相独立。
啥叫互相独立,就是子问题之间没有互相影响。
简单来说就是考试,你要拿最高分,比如一共两名,语文和数学。
要拿最高分就是数学考最高,语文考最高。这样就叫独立。
如果你数学考得高了,会导致你语文考不高,那就不叫独立。

所以要自己看看子问题之间有没有互相制约关系,是否相互独立

还有这个看待子问题的角度也非常重要。有时候你子问题找错了,那就可能做不出来了。
对于本题而言,子问题是这样拆分的,比如追求amont = 11(原问题),如果你知道凑出amont = 10的最少硬币数(子问题),那么只需要把子问题的答案(再选一枚面值为1的硬币),就是原问题的答案。还有这怎么看出子问题之间没有互相限制,因为硬币数量是没有限制的。


这里又纠正了我看待动态规划问题的思路了。一开始我是没理解倒这个问题中的独立。
1、动态规划的思考方向:
首先,动态理解是要自底向上思考的,而不是从amount=11开始往下想,我从大的开始想,那么我就会老是去想我最后一个面值为1了,那不是有可能对我前面的问题产生影响?
这里主要是方向想错了
2、子问题的定义:
对于金额i,子问题是凑出金额i所需的最少硬币数
3、独立性本质:
当我们说子问题是独立的,我们指的是,求解金额i的最优解,不依赖于如何求解i+1,i+2等更大的金额。(说白了还是方向看错了)。
4、为什么看起来不独立(我之前的思想):
因为我方向想反了。

现在来模拟这个问题
举例说明:
假设硬币面值为 [1, 2, 5],我们要凑出 11。

我们首先解决小额问题:1, 2, 3, 4, 5, …
当我们到达 11 时,我们考虑的是:
dp[11] = min(dp[10] + 1, dp[9] + 1, dp[6] + 1)
这里的 dp[10], dp[9], dp[6] 都已经是各自最优的解了
我们不是在考虑 “用1个1硬币然后解决10”,而是在比较 “10的最优解+1” 和其他可能性

独立性的证明:

如果 dp[10] 是最优的(假设是3个硬币),那么无论我们如何解决 11,都不会影响 10 的这个最优解。
即使我们选择了 “dp[9] + 1个2硬币” 作为 11 的最优解,这也不会改变 10 的最优解仍然是 3 个硬币这个事实。

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

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

相关文章

鄂维南院士:人工智能的零数据、小数据、大数据和全数据方法

源自&#xff1a; 中国计算机学会 注&#xff1a;若出现无法显示完全的情况&#xff0c;可 V 搜索“人工智能技术与咨询”查看完整文章 人工智能、大数据、多模态大模型、计算机视觉、自然语言处理、数字孪生、深度强化学习 课程也可加V“人工智能技术与咨询”报名参加学习 致…

android java socket server端 可以不断的连接断开,不断的收发 TCP转发

adb.exe forward tcp:5902 tcp:5902 前面本地5901 转发到 后面设备为5902查看转发 adb forward --list删除所有转发 adb forward --remove-allpublic static final String TAG "Communicate";private static boolean isEnable;private final WebConfig webConfig;//…

四步教你快速解决UE5文件迁移失败❗️

本期作者&#xff1a;尼克 易知微3D引擎技术负责人 不知道大家在用UE5迁移文件时&#xff0c;有没有发现这个问题&#xff1a;如果文件输出的路径选择了非项目路径&#xff0c;那么UE会提示无法迁移。在UE4中&#xff0c;这样做是不存在问题的&#xff0c;只要选择「忽略」就可…

Studying-代码随想录训练营day48| 739. 每日温度、496.下一个更大元素 I、503.下一个更大元素II

第48天&#xff0c;单调栈part01&#xff0c;栈的特殊应用场所&#xff01;编程语言&#xff1a;C 目录 739. 每日温度 496.下一个更大元素 I 503.下一个更大元素II 总结&#xff1a; 739. 每日温度 文档讲解&#xff1a;代码随想录每日温度 视频讲解&#xff1a;手撕每日…

AI识别智能称重-收银系统源码

系统概况 专门为零售行业的连锁店量身打造的收银系统&#xff0c;适用于常规超市、生鲜超市、水果店、便利店、零食专卖店、服装店、母婴用品、农贸市场等类型的门店使用。同时线上线下数据打通&#xff0c;线下收银的数据与小程序私域商城中的数据完全同步&#xff0c;如商品…

什么是数据血缘?怎么做好数据血缘分析?

目录 一、什么是数据血缘&#xff1f; 二、数据血缘关系的四大特征 三、数据血缘分析怎么做&#xff1f; 1.定义元数据模型 2.收集元数据 3.建立血缘关系模型 4.追踪数据流动 5.可视化分析 6.集成到数据治理中 7.持续更新和维护 8.应用分析结果 四、数据血缘技术趋势 1.通用的血…

测试环境领域到测试环境产品

作者&#xff1a;攻心 去年之前&#xff0c;阿里巴巴的淘天集团测试环境是以领域方式运作&#xff1a;不局限测试环境治理本身&#xff0c;从测试模式方法论及用好测试环境思路引领集团测试环境治理。领域运作最难的是“统一思想”。业务进一步细分调整后&#xff0c;测试环境治…

修改所属用户/用户组——chown

目录 &#xff08;1&#xff09;修改所属用户 &#xff08;2&#xff09;修改所属用户组 &#xff08;3&#xff09;修改所属用户和用户组 &#xff08;4&#xff09; 选项 -R 使用 chown 可以修改文件/文件夹的所属用户&#xff0c;所属用户组&#xff1b; 当然与 chmod …

数字人直播系统搭建能力评测!3招教你快速摸清源码厂商的真实实力?

随着数字人直播的应用场景不断拓展和应用频率的持续升高&#xff0c;其所蕴含着的市场前景和收益潜力逐渐显现&#xff0c;连带着数字人直播系统搭建的热度也迎来了新的高潮。在此背景下&#xff0c;作为非科班和研发资源有限的创业者们主要的入局途径&#xff0c;各大数字人源…

C++原创系列创斯人工智能Trons10.0.135.7911最新概念版本预告及思路总结

这次更新删掉了以前的所有代码&#xff0c;重新编写&#xff0c;只因我有了新的思路&#xff0c;以前的思路太过于原始&#xff0c;我的思路中的聊天功能如下 这只是聊天函数的原理&#xff0c;聊天函数对一句话的回答有5个到10个&#xff0c;在主函数中多次运行这个函数&#…

ruoyi vue3版本web端隐藏侧边栏及其顶部导航栏

做项目时有个需求是在web端里面嵌入一个页面全屏的大屏&#xff0c;但若依web自带的侧边栏导航和顶部导航一时还不知道怎么隐藏起来&#xff0c;于是在网上到处查找资料&#xff0c;终于&#xff0c;还是在若依的gitee文档中发现了线索 怎么隐藏侧边栏和顶部导航栏实现完全的全…

<数据集>工程机械识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;6338张 标注数量(xml文件个数)&#xff1a;6338 标注数量(txt文件个数)&#xff1a;6338 标注类别数&#xff1a;7 标注类别名称&#xff1a;[Excavator, Loader, Dumb_truck, Mobile_crane, Roller, Bull_dozer, …

微信小程序之使用智能对话服务,客服回复的跳转小程序指定页面链接无效

在微信小程序中使用了微信智能对话服务&#xff0c;客服回复的是小程序指定页面的链接&#xff0c;无法正确跳转&#xff0c;而是返回到进入客服时的页面去了 解决方案&#xff1a; 需在小程序的客服组件 button 上添加 bindcontact 监听事件即可 <movable-area class"…

【ROS 最简单教程 007/300】ROS 架构 - 目录解析 增删改查 计算图

⭐ 工作空间目录解析如下 &#xff1a; WorkSpace --- 自定义的工作空间|--- build:编译空间&#xff0c;用于存放 CMake 和 catkin的 缓存信息、配置信息和其他中间文件|--- devel:开发空间&#xff0c;用于存放编译后生成的目标文件&#xff0c;包括头文件、动态&静态链接…

MySQL基础练习题14-产品销售分析1

题目&#xff1a;获取 Sales 表中所有 sale_id 对应的 product_name 以及该产品的所有 year 和 price 。 准备数据 分析数据 题目&#xff1a;获取 Sales 表中所有 sale_id 对应的 product_name 以及该产品的所有 year 和 price 。 准备数据 ## 创建库 create database db;…

DNS查询服务器的基本流程以及https的加密过程

DNS查询服务器的基本流程&#xff0c;能画出图更好&#xff0c;并说明为什么DNS查询为什么不直接从单一服务器查询ip&#xff0c;而是要经过多次查询&#xff0c;多次查询不会增加开销么&#xff08;即DNS多级查询的优点&#xff09;&#xff1f; 用户发起请求&#xff1a;用户…

Linux 修改磁盘挂载的目录路径

确认新路径地址&#xff0c;能找到&#xff0c;或者mkdir新创建新路径&#xff0c;考虑权限 #查看当前挂载情况 df -h 卸载已经挂载的目录 umount /media/vdtest #挂载新目录 mount /dev/vdb /mnt #查询/dev/vdb的UUID blkid /dev/vdb #修改 fstab文件实现开机自动挂载&…

Spring源码解析(25)之AOP的BeanDefinitiion准备

一、AOP代码准备 aop.xml文件准备&#xff0c;代码如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance…

汇川技术|CANlink、CANopen、Profibus-DP网络编辑器的使用

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 本节学习CANlink、CANopen、Profibus-DP网络编辑器的使用。 以下为学习笔记。 01 CANlink编辑器 在AC810的【网络组态】中未看到CANlink主站的功能&#xff0c;所以先简单了解&#xff0c;等具体使用时再具体查看。 …

2025上海国际显示技术及应用创展览会

DIC EXPO2025中国&#xff08;上海&#xff09;国际显示技术及应用创展览会 时间&#xff1a;2025年8月7-9日 地点&#xff1a;上海新国际博览中心 主办单位&#xff1a; 中国光学光电子行业协会液晶分会 联合主办&#xff1a; 中国电子材料行业协会 中国电子商会 韩国…