eetcode必要技巧--动态规划(一)
首先我们要搞清楚什么是动态规划
动态规划是运筹学中用于求解决策过程中的最优化数学方法。当然,我们在这里关注的是作为一种算法设计技术,作为一种使用多阶段决策过程最优的通用方法。
当然这个很难理解,但是按照本人的理解.
实际上就是一个种类的问题.
在这个问题中,我们只需要列出一个方程,就能用递归的方法解决大部分呢问题.
(突然看到一个不错的消息)
动态规划问题的一般形式就是求最值。动态规划其实是运筹学的一种最优化方法,只不过在计算机问题上应用比较多,比如说让你求最长递增子序列呀,最小编辑距离呀等等。
既然是要求最值,核心问题是什么呢?求解动态规划的核心问题是穷举。因为要求最值,肯定要把所有可行的答案穷举出来,然后在其中找最值呗。
作者:labuladong
链接:https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-tao-lu-xiang-jie-by-wei-lai-bu-ke/
来源:力扣(LeetCode)
总结一下,就是对整个内容进行穷举操作,恰好这种穷举操作有着大量的可重复性,可以利用递归来解决.
个人认为动态规划有俩个核心
- 递归
- 冗余处理
我们就用leetcode中的零钱兑换.
给定不同面额的硬币 coins 和一个总金额 amount。
编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。
这里还要引申一下,一开始我想到的算法使用amount(总金额)%5(coins中最大的硬币)得出余数(在这里假设为remainder).
再用remainder(上面得出的数)%2(coins中第二大的硬币面值)不断地循环下去.
据说这叫贪心算法.
这个无疑是错误的.比如[1,5,11] 凑15
那么按照这个贪心算法的唯一结果是 一个11和4个1
但是正确的答案是三个5
这就是这种算法的局限性
说回正题
要想解决问题,我们就必须分析这个问题.
我们就必须化出解决这个问题的穷举图像

这里说一下,这个也是从leetcode上拿的.
我们看这个图像,最上面有一行小字,翻译如下:
emmm英语不好,挑重点说吧
[1,2,3]种面值的币子
凑6
我们会发现如果要遍历这个树,就会发现每一个节点执行的操作实际上都是大同小异的,而且面对的数据也都是大同小异的(都是那三个数,1,2,3都不会变化)
所以也正是因为如此.我们可以采用.递归的方式.
在这里就要说到处理这种方式的诀窍了.如果按照递归的思路一直深究下去,那么唯一的结果就是蒙圈.
毕竟太深入,太复杂了.
可是我们要意识到,其实这个算法再每一个节点上都是相同的,都可以用一样的算法.于是我们只要列出第一层和第二层之间的关系就可以用这个关系为突破口,想办法用递归实现这个问题.
F(S)=F(S-C)+1;
F(S):所要求的目标->最少的硬币个数
S:总金额
c:(所用)最后一个硬币的面值
eg:
在最顶层 6节点开始有以下三种情况
F(6)=F(6-1)+1=F(5)+1
F(6)=F(6-2)+1=F(4)+1
F(6)=F(6-3)+1=F(3)+1
我们要知道其中F(5)因为也是一个函数所以,也会向下裂变化为
F(5)=F(5-1)+1
F(5)=F(5-2)+1
F(5)=F(5-3)+1
然后面还可以裂变,直到s-c=0或者s-c<0为止(这就是我们迭代的停止条件,s-c>0)
这就是用迭代形成了一个遍历的过程.相比while这种方式,方便了很多倍.[这个遍历的实质上得出的是每一条可能出现的路径所要消耗的硬币数量]
但是我们遍历的目的是为了找出一条最短的路径,使用最少的硬币数量,所以我们需要对其进行比较.
也就是在
--A代码块
F(6)=F(6-1)+1=F(5)+1
F(6)=F(6-2)+1=F(4)+1
F(6)=F(6-3)+1=F(3)+1
---
这三个可能中选择最小的一个.
F(S)是最少硬币的个数.
而如果要求出这三个我们就要知道F(5,4,3)[简写]中谁最小.于是这就要到了,我们要知道
F(5)=F(5-1)+1
F(5)=F(5-2)+1
F(5)=F(5-3)+1
种谁最小的问题.
完全是一摸一样的,这就是递归最好的温床.
//coins 硬币面值(是个数组,在迭代过程中从不变化)
//rem 总值就是S
//count[] 记录的信息(这个是为了防止重复计算的问题)
//这个for就是找出A代码块中那个线路最小的步骤,存在min中
for (int coin : coins) {
int res = coinChange(coins, rem - coin, count);
//F(S)=F(S-C)+1;
//rem-coin对应的就是S-C
if (res >= 0 && res < min)
//min的结果实际上就是最小的res+1就是F(S).而res实际上是
min = 1 + res;
//F(S)=F(S-C)+1;
//res=function(coins,S-C,count);
//min=function(coins,S-C,count)+1;
}
代码看到这里我们就知道了这个部分我们已经完全实现了这个式子中所要求的一切.
我们所要做的其实就是复刻你列出的式子.
不必想的太深.
当你发现他们每个节点高度的统一性的时候,其实只要解决其中一个节点,剩下的节点就都解决了.
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/coin-change/solution/322-ling-qian-dui-huan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这里贴一下完整的代码
class Solution {
public int coinChange(int[] coins, int amount) {
// if(amount<1)
return coinChange(coins,amount,new int[amount]);
}
在这里我们会发现我们的要想递归就只能拿这个函数制作递归,但是s-c就无法实现了,所以我们只能重载一个.让这个最终返回内容.
//coins 硬币面值
//rem 总值
//count[] 记录的信息
private int coinChange(int [] coins,int rem,int [] count){
if(rem==0) return 0;//解决输入不合理
if(rem<0)return -1;//解决输入合理
if(count[rem-1]!=0){return count[rem-1];}//如果以前已经有了记录,就返回被记录的数值
int min=Integer.MAX_VALUE;
for(int i=0;i<coins.length;i++){
int res=coinChange(coins,rem-coins[i],count);//递归,如果以前有了相关的内容会直接反回
//如果是最小的,那么就加1,作为最少币数
if(res>=0&&min>res){
min=res+1;
}
}
//min有没有被改变,要是改变了就不会是原值,自然回min
count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min;
return count[rem - 1];
}
}
eetcode必要技巧--动态规划(一)的更多相关文章
- 书评<<剑指offer 名企面试官精讲典型编程题>>
前前后后阅读了一周, 感慨很多, 面试考察的是一个人的综合能力, 这一点从面试官的角度去解读, 确实对面试的理解更立体. *) 具体考察的点1) 扎实的基础2) 高质量的代码3) 清晰的思路4) ...
- BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 有\(n\)个工厂,给出第\(i\)个工厂的到1号工厂的距离\(x[i]\),货物数量\ ...
- 【动态规划技巧题】POJ2229-Sumsets
[题目大意] 把一个数n分成2的指数幂相加的形式,问有几种情况. [思路] 如果当前i为奇数,则必定有至少一个1,可以看作i-1的情形再加上一个1.即f[i]=f[i-1]. 如果当前i为偶数,假设没 ...
- 动态规划 Dynamic Programming
March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...
- Floyd 算法的动态规划本质
[转载自:http://www.cnblogs.com/chenying99/p/3932877.html] Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(A ...
- 动态规划 算法(DP)
多阶段决策过程(multistep decision process)是指这样一类特殊的活动过程,过程可以按时间顺序分解成若干个相互联系的阶段,在每一个阶段都需要做出决策,全部过程的决策是一个决策序列 ...
- poj 动态规划题目列表及总结
此文转载别人,希望自己能够做完这些题目! 1.POJ动态规划题目列表 容易:1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 11 ...
- poj动态规划列表
[1]POJ 动态规划题目列表 容易: 1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 1189, 1208, 1276, 13 ...
- 集合上的动态规划---最优配对问题(推荐:*****) // uva 10911
/* 提醒推荐:五星 刘汝佳<算法竞赛入门经典>,集合上的动态规划---最优配对问题 题意:空间里有n个点P0,P1,...,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点 ...
随机推荐
- Redis实现高并发分布式锁
分布式锁场景在分布式环境下多个操作需要以原子的方式执行首先启一个springboot项目,再引入redis依赖包: <!-- https://mvnrepository.com/artifa . ...
- FFT(快速傅里叶变换) 模板
洛谷 P3803 [模板]多项式乘法(FFT)传送门 存个板子,完全弄懂之后找机会再写个详解. #include<cstdio> #include<cmath> struct ...
- mysql 优化一
从几个方面出发: ① 数据库设计② sql语句优化③ 数据库参数配置④ 恰当的硬件资源和操作系统 下面详细介绍: ① 数据库设计 通俗地理解三个范式,对于数据库设计大有好处.在数据库设计中,为了更好地 ...
- [LC] 359. Logger Rate Limiter
Design a logger system that receive stream of messages along with its timestamps, each message shoul ...
- sql 优化之8个尽量
查询语句的优化是SQL效率优化的一个方式,可以通过优化sql语句来尽量使用已有的索引,避免全表扫描,从而提高查询效率.最近在对项目中的一些sql进行优化,总结整理了一些方法. 1.在表中建立索引,优先 ...
- Serializable 接口(序列化)
目录 Serializable 接口(序列化) 前言 用途 如何实现 异常 serialVersionUID transient关键字 Serializable 接口(序列化) 前言 查看API文档时 ...
- MyBatis 逆向工程介绍
1. 概念: 逆向工程就是根据数据库中对应的表在项目工程中生成相应的MyBatis代码(XXXMapper.java/XXXMapper.xml/Moudle(XXX)),逆向工程生成的代码可以进行简 ...
- Ionic3学习笔记(十)实现夜间模式功能
本文为原创文章,转载请标明出处 目录 创建主题样式 导入 variables.scss 创建 provider 创建 page 在 App 入口处应用主题 效果图 1. 创建主题样式 在 ./src/ ...
- Introduction Of Gradient Descent
不是一个机器学习算法 是一种基于搜索的优化方法 作用:最小化一个损失函数 梯度上升法:最大化一个效用函数 import matplotlib.pyplot as plt import numpy as ...
- Html的label和span的区别
从最终效果来看,label与span标签显示方式及作用都一样的但由于label中有for属性的存在,也有着决定性的不同 for属性将label和表单进行配对 label标签通常是写在表单(form)内 ...