首先我们要搞清楚什么是动态规划

动态规划是运筹学中用于求解决策过程中的最优化数学方法。当然,我们在这里关注的是作为一种算法设计技术,作为一种使用多阶段决策过程最优的通用方法。

当然这个很难理解,但是按照本人的理解.

实际上就是一个种类的问题.

在这个问题中,我们只需要列出一个方程,就能用递归的方法解决大部分呢问题.

(突然看到一个不错的消息)

动态规划问题的一般形式就是求最值。动态规划其实是运筹学的一种最优化方法,只不过在计算机问题上应用比较多,比如说让你求最长递增子序列呀,最小编辑距离呀等等。

既然是要求最值,核心问题是什么呢?求解动态规划的核心问题是穷举。因为要求最值,肯定要把所有可行的答案穷举出来,然后在其中找最值呗。

作者:labuladong

链接:https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-tao-lu-xiang-jie-by-wei-lai-bu-ke/

来源:力扣(LeetCode)

总结一下,就是对整个内容进行穷举操作,恰好这种穷举操作有着大量的可重复性,可以利用递归来解决.

个人认为动态规划有俩个核心

  1. 递归
  2. 冗余处理

我们就用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必要技巧--动态规划(一)的更多相关文章

  1. 书评<<剑指offer 名企面试官精讲典型编程题>>

      前前后后阅读了一周, 感慨很多, 面试考察的是一个人的综合能力, 这一点从面试官的角度去解读, 确实对面试的理解更立体. *) 具体考察的点1) 扎实的基础2) 高质量的代码3) 清晰的思路4) ...

  2. BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 有\(n\)个工厂,给出第\(i\)个工厂的到1号工厂的距离\(x[i]\),货物数量\ ...

  3. 【动态规划技巧题】POJ2229-Sumsets

    [题目大意] 把一个数n分成2的指数幂相加的形式,问有几种情况. [思路] 如果当前i为奇数,则必定有至少一个1,可以看作i-1的情形再加上一个1.即f[i]=f[i-1]. 如果当前i为偶数,假设没 ...

  4. 动态规划 Dynamic Programming

    March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...

  5. Floyd 算法的动态规划本质

    [转载自:http://www.cnblogs.com/chenying99/p/3932877.html] Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(A ...

  6. 动态规划 算法(DP)

    多阶段决策过程(multistep decision process)是指这样一类特殊的活动过程,过程可以按时间顺序分解成若干个相互联系的阶段,在每一个阶段都需要做出决策,全部过程的决策是一个决策序列 ...

  7. poj 动态规划题目列表及总结

    此文转载别人,希望自己能够做完这些题目! 1.POJ动态规划题目列表 容易:1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 11 ...

  8. poj动态规划列表

    [1]POJ 动态规划题目列表 容易: 1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 1189, 1208, 1276, 13 ...

  9. 集合上的动态规划---最优配对问题(推荐:*****) // uva 10911

    /* 提醒推荐:五星 刘汝佳<算法竞赛入门经典>,集合上的动态规划---最优配对问题 题意:空间里有n个点P0,P1,...,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点 ...

随机推荐

  1. fcntl()函数之非阻塞模型

    优点:设置标准输入为非阻塞(有数据则读 没有数据则立即返回),常用于网络通信以及轻量信息多并发中 步骤: 1.oldflag=fcntl(STDIN_FILENO,F_GETFL); 获取标准输入的文 ...

  2. 洛谷-P3919-可持久化数组

    题目传送门 sol:在洛谷上看到一种dfs + 离线的方法,可以解决大部分可持久化问题.把依赖关系看成边,然后建树.这样本来要解决的多个版本只要在一个版本上进行修改就好了. 离线 + dfs #inc ...

  3. 关于MyBatis的运行原理(转载)

    1.获取sqlSessionFactory对象: 解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSessionFactory: 注意: ...

  4. JarvisOJ level3_x64

    这一题是和前面x86的差不多,都是利用了同一个知识点,唯一的区别就是使用的堆栈地址不同,x86是直接使用堆栈来传递参数的,而x64不同 x64的函数调用时整数和指针参数按照从左到右的顺序依次保存在寄存 ...

  5. [LC] 142. Linked List Cycle II

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To r ...

  6. [LC] 242. Valid Anagram

    Given two strings s and t , write a function to determine if t is an anagram of s. Example 1: Input: ...

  7. redis下载安装及php配置redis

    下载及安装redis 1.首先去github网站上下载https://github.com/dmajkic/redis/downloads: 2.根据实际情况,将64bit的内容cp到自定义盘符目录, ...

  8. 一下午简单写个搭建Flutter开发环境,dome跑起来!

    1.下载flutter包由于需要翻墙,国内下载会出现问题,所有需要先配置一下用户环境变量. export PUB_HOSTED_URL=https://pub.flutter-io.cn export ...

  9. html常用事件

    1.onblur 当窗口失去焦点时运行 2.click 点击鼠标触发的事件 3.onfocus 当窗口获得焦点时运行 4.oninput 当元素获得用户输入时运行 5.onsubmit 当提交表单时运 ...

  10. MySQL树形结构的数据库表设计和查询

    1.邻接表(Adjacency List) 实例:现在有一个要存储一下公司的人员结构,大致层次结构如下: 那么怎么存储这个结构?并且要获取以下信息: 1.查询小天的直接上司. 2.查询老宋管理下的直属 ...