| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 【算法题】LeetCode-硬币划分问题-(动态规划、斜率优化、空间压缩) -> 正文阅读 |
|
[数据结构与算法]【算法题】LeetCode-硬币划分问题-(动态规划、斜率优化、空间压缩) |
今天来看一道关于动态规划的算法题:硬币划分问题。LeetCode链接
一、暴力递归进行尝试解法可能很多的人,拿到这道题,都不知道该如何进行下手,没有任何的思路。我也是一样的,只能先尝试着用暴力的方法,去写尝试的方法。 既然有一些硬币,那么我们就先用一个数组,将所有硬币的面值存储起来,切记,这里有一个潜规则:硬币在数组中的顺序,一定是按大小顺序进行排序的,要么是升序,要么是降序。
然后就是我们要知道一个情况就是:假设n=10,硬币的组合方式有一种是1+1+1+1+1+5,这样一种方式,其实等价于这样:1+5+1+1+1+1。这两种,实则指的就是一种情况。根据这个情况,我们可以很明显的发现一个问题,那就是在使用硬币的时候,相同的硬币最好是在一起使用,也就是说不要出现上面一个5,将1分割成了两部分,如下图: 那要做到上图的理想情况,那就是在使用一种硬币的时候,保证一次性拿够(数量)。 在面对每一种硬币时,也就是在coins[i]时,当前这个位置的硬币,我可以选择要和不要两种情况。 所以根据上面分析,我们能够得出一个暴力递归的解法。
以上就是递归的版本,核心就在于,相对于每一种硬币来说,我可以选择不要,又或者是要1个,或者是2个……,以这样的方式,一个一个的去尝试,这非常的暴力。 递归版本的代码,可能会出现大量的重复计算,因此就出现了动态规划。动态规划的本质就是在给递归做优化,把可能会进行重复计算的数值,保存到一张表中,下次需要这种状态的值的时候,直接从表里面拿取即可。 二、经典的dp解法我们可以根据递归的版本,进行添加缓存,来达到一个优化。
现在dp表建好之后,就是如何进行填写这张表??? 非常简单,递归版本的代码是怎么写的,dp表就该怎么填写。 1、base case先看递归的结束条件,有两种情况:
所以在dp表的最后一行中,只有当cur=n的时候,方法数才是1,也就是右下角位置(dp【最后一行】【最后一列】)的值是1。最后一行其他的位置的值,都是0。
2、普遍位置的推导我们先来看填写好base case代码之后,整体代码是样子的。
在填写好base case之后,我们就需要进行其他中间位置的数值了。再次看递归版本的代码: 现在我们只需要将上图的普遍位置的填写,这段代码,写到上一段代码的两层for循环即可。然后将process改为dp表即可,如下:
切记切记,递归的代码是怎么写的,dp表里面就怎么填。我们只需要将递归函数的子过程,从dp表中取数据即可。取模运算是题意要求取模的。 总结:本质上,动态规划就是在将递归函数做的事,进行简化,递归函数可能去计算时,要递归多次,但是动态规划不一样,只需要在dp表中,直接拿取相应位置的数据即可。 三、斜率优化其实上面写的dp,只是较为经典的写法,本质上,这段代码还是存在一定的小问题,那就是存在枚举问题,也就是说,效率还不够高。还可以进行优化。如下图: 如上图所示,假设需要计算五角星位置的值,它所在的行是1,也就是2分钱的硬币,它所在的列是5,也就是当前有5分钱。根据递归函数可知,它依赖于dp【index+1】【cur】+ dp【index + 1】【cur + 2】+ dp【index+ 1】【cur + 4】……。 也就是说,它的数值,就等于它下一行的某些位置的数据进行求和。而具体下一行的哪些位置,取决于五角星的所在行,拿上图的举例,五角星的行数是1,对应的硬币面值是2,所以从五角星下面一行(dp【index】【cur】)位置开始,往右边进行求和,每次向右跳两个格子。这样的代码还不叫斜率优化,这只是一个依赖关系的推导,我们先来看看代码,其实和上文中的经典dp的解法一个意思,这里只是为了铺垫后续的斜率优化。 在上文的经典dp代码中,我们的列数,是从左往右计算的,此时我们需要稍微改一下。改成从右往左计算。如下:
上诉代码,就是将列(money),改为从右向左计算的。跟原来的没啥区别,重点就来了。好好看一下图: 红色三角形位置的数值,求和,也是依赖于它下一行的某些位置的数据。很明显可以看出来,这些数据跟五角星的求和时,有很多都是来自同一个位置的数据,比如上图的dp【2】【7】+dp【2】【9】。也就是说,在计算五角星的时候,其实红色三角形位置的数据,已经帮我们计算过了,我们只需要从红色三角形位置拿取数据,然后再加上五角星下边的数据,就能得到五角星的数据啦。这样的优化,就称为斜率优化。 代码如下:
以上的代码,就是斜率优化之后的代码,是不是很简单呢? 四、dp空间压缩说到这里,我相信很多同学都已经知道这道题的整体思路了,空间压缩也就很简单了。整张dp表的填写,我们都是从最后一行开始填写,一直填写到第一行,然后第一行的第一个数据就是最终的答案。 并且我们还可以知道,计算普遍位置的时候,比如五角星的时候,我们只用到了五角星下面的一行数据。像这样的,依赖关系只来自于有限的行数据,那么就可以进行空间压缩。我们只需要建立一个一维数组,就解决这道题。 整体的思路,还是从最后一行开始填写,从下往上,从左往右填写:
好啦,以上全部就是本道题的全部讲解啦!!!如若文中有误,还望大家能够指正出来。又或者大家还有什么疑惑的地方,我们在评论区见吧!!!下期再见啦,拜拜!!! |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 16:29:50- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |