在本文中,我们先用最简单的方法来解决问题,然后一步步进阶,在这个不断优化算法的过程中理解动态规划。

力扣 322. 零钱兑换 问题

  1. 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
  2. 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。【你可以认为每种硬币的数量是无限的。】
public int coinChange(int[] coins, int amount) {}

1. 暴力递归

假设 coins[] = [2, 4, 5],amount = 10,想要求 amount = 10 可以求
min ( 1 + coinChange(coins, amount - 2), 1 + coinChange(coins, amount - 4), 1 + coinChange(coins, amount - 5) )

即假设已经知道了 amount = 8、amount = 6、amount = 5 时 所需的最少的硬币个数, 那只要再加 1 个硬币就可以凑够 10,在这三者中选最少的一个就是答案。

继续想的话,求 amount = 8,也是同样的方法,就是不断往下递归。

public int coinChange(int[] coins, int amount) {//确定递归结束的条件if(amount == 0) return 0;if(amount < 0) return -1;int res = Integer.MAX_VALUE;//遍历求各 coinChange(amount-coin) 的值,求出最小值for(int coin: coins){int subProblem = coinChange(coins, amount-coin);if(subProblem == -1) continue;res = Math.min(res, subProblem + 1);}return res==Integer.MAX_VALUE ? -1 : res;
}

为了更好理解,来画一下递归树


从上图就可以看出来,这种方法就是在用递归把所有的可能穷举出来,然后取最小值。

但这个方法存在重叠子问题,即存在大量的重复计算。有很多问题我们已经计算过,但当递归到那里时,还是要再算一次。

所以为解决这个问题,下面采用带备忘录的递归解法。

2. 带备忘录的递归解法

带备忘录就是把已经计算过的值存起来,以此来减少不必要的计算。

每次计算完后,将值存入一个数组中,每次计算前判断一下备忘录中有没有存,有则可以直接获取,不需要再进行漫长的递归运算了。

int[] count;
public int coinChange(int[] coins, int amount) {//建立数组,进行初始化count = new int[amount+1];Arrays.fill(count, -2);return(coin(coins, amount));
}
public int coin(int[] coins, int amount){if(amount == 0) return 0;if(amount < 0) return -1;//判断是否存入备忘录if(count[amount] != -2)return count[amount];int res = Integer.MAX_VALUE;for(int coin:coins){int subProblem = coin(coins, amount-coin);if(subProblem == -1) continue;res = Math.min(res, subProblem+1);}//存入count[amount] = (res == Integer.MAX_VALUE) ? -1 : res;return count[amount];
}

现在似乎已经很完善了,但备忘录解法是 自顶向下 的,是从一个规模较大的原问题,一层一层向下分解成子问题,直至底层,然后再逐层返回结果。

动态规划是 自底向上 的解出最优值。下面来改造一下这个方法。

3. dp 数组的迭代解法

采用 自底向上 就是要从底层状态一直算到所求状态
定义一个 dp 数组,dp[i] 表示为 amount = i 时所需的最少的硬币个数

public int coinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];Arrays.fill(dp, amount + 1);dp[0] = 0;// 外层 for 循环在遍历所有状态的所有取值// 然后存入 dp[i] 中for(int i=1; i<dp.length; i++){for(int coin: coins){if(i-coin < 0) continue;dp[i] =Math.min(dp[i], 1 + dp[i-coin]);}}return dp[amount] == amount + 1 ? -1 : dp[amount];
}

这就是最后的动态规划的解法了。

动态规划最核心的是写出状态转移方程,这也是最困难的一步,多多练习,熟能生巧。

本文源于学习 labuladong的算法小抄 ,大佬写的明白易懂,没有什么晦涩的地方。

一个简单的例子由易到难理解动态规划相关推荐

  1. java继承类型转换_#java 一个简单的例子理解java继承、成员函数重写、类型转换...

    一个简单的例子理解java继承.成员函数重写.类型转换 1.继承简介 举一个简单的例子:笔分为很多种,比如毛笔.钢笔.圆珠笔等等,这些笔都有一些相同的属性比如长度.笔迹的粗细等等:但他们也有不同的特点 ...

  2. 抽象语法树 c语言,一个简单的例子看懂抽象语法树的魔力

    在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示.它以树状的形式表现编程语言的语法结构,树上的每个 ...

  3. 量子运算 简单通俗例子_什么是量子计算机? 用一个简单的例子解释。

    量子运算 简单通俗例子 by YK Sugi 由YK Sugi 什么是量子计算机? 用一个简单的例子解释. (What is a quantum computer? Explained with a ...

  4. React.js 小书 Lesson1-2 - 前端组件化(一):从一个简单的例子讲起

    React.js 小书 Lesson1-2 - 前端组件化(一):从一个简单的例子讲起 本文作者:胡子大哈 本文原文:http://huziketang.com/books/react/lesson2 ...

  5. 一个简单的例子解释什么是量子计算机

    大家好! 前几天,我访问了加拿大温哥华的D-Wave Systems.这是一家制造尖端量子计算机的公司. 我在那里学到了很多关于量子计算机的知识,所以我想在这篇文章中与你们分享我在那里学到的一些东西. ...

  6. 一步一步解读神经网络编译器TVM(一)——一个简单的例子

    @TOC 前言 这是一个TVM教程系列,计划从TVM的使用说明,再到TVM的内部源码?为大家大致解析一下TVM的基本工作原理.因为TVM的中文资料比较少,也希望贡献一下自己的力量,如有描述方面的错误, ...

  7. .net中的对象序列化(1): 序列化是什么, 以及一个简单的例子

    1. 为什么需要序列化,什么是序列化 对于一个程序来说, 使用到的对象都是存在于内存中的.如果想保存这些对象的运行时状态, 或者需要在不同进程或者网络间传递对象,就需要序列化. 序列化就是讲运行中的对 ...

  8. 一个简单的例子看java线程机制

    一个简单的例子看java线程机制 作者: zyf0808 发表日期: 2006-03-26 11:20 文章属性: 原创 复制链接 import java.util.*; public class T ...

  9. blockchain 区块链200行代码:在JavaScript实现的一个简单的例子

    blockchain 区块链200行代码:在JavaScript实现的一个简单的例子 了解blockchain的概念很简单(区块链,交易链块):它是分布式的(即不是放置在同一台机器上,不同的网络设备上 ...

  10. pycharm安装scrapy失败_Scrapy ——环境搭配与一个简单的例子

    在我刚接触爬虫的时候就已经听过Scrapy大名了,据说是一个很厉害的爬虫框架,不过那个时候沉迷于Java爬虫.现在终于要来揭开它神秘的面纱了,来一起学习一下吧 欢迎关注公众号:老白和他的爬虫 1.环境 ...

最新文章

  1. tar 解压缩命令详解
  2. 使用ODBC连接SQL Anywhere 5.0(asp)
  3. window上安装mysql服务核心版(亲测可用)
  4. 软件测试java三角形形状判定,软件测试技术基础实验——Junit 安装与 三角形问题的测试...
  5. IOS中获取屏幕尺寸
  6. freeswitch 会议创建命令
  7. 图——基本的图算法(四)关键路径
  8. Rockchip_双屏显示旋转方向调试文档
  9. FFmpeg[14] - ffbuild/common.mak:173: *** missing separator. Stop.
  10. python画速度等值线图_python画contour图
  11. 第十二周项目5-迷宫问题之图深度优先遍历解法
  12. 计算机视觉笔记11.26
  13. 看机器学习如何还原图像色彩
  14. bibitem排版引用顺序不正确,最后一页两栏平衡
  15. Nodejs:ESModule和commonjs,傻傻分不清
  16. 四位“计算机之父”之争
  17. 申请国外博士后的好网站
  18. HTML Tab选项卡
  19. 四足爬行机器人运动_四足爬行机器人控制研究
  20. 电脑如何批量修改图片350dpi? 分享一款实用的在线图片处理工具

热门文章

  1. 设计任务调度依赖配置表
  2. 2021年茶艺师(初级)考试题库及茶艺师(初级)作业考试题库
  3. V模型、W模型、H模型示意图以及优缺点对比
  4. iOS加速器简单介绍
  5. 第8节 破解系统密码—利用win7漏洞和PE系统破解密码
  6. 中国近代史-蒋廷黻-笔记-第一章-剿夷与抚夷-第二节-英国人做鸦片买卖
  7. 江西省中小学生学籍管理-登录(1)
  8. 《MIT科技评论》“35位35岁以下科技创新青年”名单出炉!AI领域有5人入选 | 2020中国区...
  9. python编写直角三角形边长公式_python 打印直角三角形,等边三角形,菱形,正方形的代码...
  10. 显示器选购参数解析-为了给笔记本买个外接显示器,我的笔记本核显支持4K60Hz吗