文章目录

  • 一、题目描述
  • 二、解题思路(最朴素方法)
    • 1. 定义状态
    • 2. 定义状态转移方程
    • 3. 初始化
  • 三、代码实现
  • 四、优化
  • 五、执行结果

一、题目描述

​ 在美国,硬币按照面值1,5,10,25,50来铸造(单位为美分)。现在考虑按照面值{d1,…, dk}(单位为分)来铸造硬币的某个国家.我们想统计有多少种方式能找开n分钱,并记种数为C(n)。例如当所在国家硬币面值集合为{1,6,10}时,C(5)=1,C(6)到C(9)都是2,C(10)=3,C(12)=4。

​ 给出一种高效算法来算出C(n)并分析该算法的时间/空间复杂度。(提示:通过计算C(n,d)来解决问题,C(n,d)是最高面值为d情况下能找开n分钱的方式种数.千万注意不要重复计数.)

​ ———题目来源:《算法设计指南》

示例:

输入:coins = [2,3,5] total = 10
输出:4
解释:2 + 3 + 5是一种2 + 2 + 3 + 3是一种2 + 2 + 2 + 2 + 2 + 2是一种5 + 5是一种总共4种。

二、解题思路(最朴素方法)

1. 定义状态

​ 设dp[i][j]表示使用前i个面值不同的硬币找出零钱j的方案数。

2. 定义状态转移方程

dp[i][j]=∑k=0n(dp[i−1][j−k×di])dp[i][j] = \sum_{k=0}^{n}(dp[i - 1][j - k \times d_i]) dp[i][j]=k=0∑n​(dp[i−1][j−k×di​]) ,其中n=⌊jdi⌋n = \lfloor \frac{j}{d_i} \rfloor n=⌊di​j​⌋ 。这里解释一下dp[i−1]dp[i-1]dp[i−1]表示使用前i−1i-1i−1个面值不同的硬币,其中第iii个硬币可能使用0个或多个,上限为⌊jdi⌋\lfloor \frac{j}{d_i} \rfloor⌊di​j​⌋ 个,下限为0个。

3. 初始化

​ dp[0][j]表示不使用硬币找出j的方案数,根据实际情况是找不出来的,故初始化为0。

​ dp[i][0]表示使用前i个面值不同硬币找出0美分的方案数量,很显然dp[i][0]初始化为1即可。

三、代码实现

/*** 第8章第7题 找零钱问题** @author hh*/
public class Solution {/***找零钱的方案数** @param coins 硬币面值集合* @param total 找的零钱总数* @return 方案数*/public int exchange(int[] coins,int total) {int[][] dp = new int[coins.length + 1][total + 1];//dp[0][i] = 0,i > 0时for(int i = 1; i <= total; i++){dp[0][i] = 0;}for(int i = 0; i <= coins.length ; i++){dp[i][0] = 1;}for(int i = 1; i <= coins.length ; i++){for(int j = 1; j <= total ; j++){dp[i][j] = 0;for(int k = 0; k <= (j / coins[i -1]) ; k++){dp[i][j] += dp[i-1][j - k * coins[i - 1]];}}}return dp[coins.length ][total];}public static void main(String[] args){Solution solution = new Solution();int[] coins = new int[]{2,3,5};int total = 10;System.out.println(solution.exchange(coins,total));}}

四、优化

对于解题思路中的k其实是没必要计算的,这样就减少了一个循环。状态方程变为:

​ dp[i][j]=sum(dp[i−1][j],dp[i][j−di])dp[i][j] = sum(dp[i - 1][j],dp[i][j - d_i]) dp[i][j]=sum(dp[i−1][j],dp[i][j−di​])

表示的含义是前i-1种硬币凑成j的方案数加上前i种硬币凑成j - di的方案数。第二个式子表示最少有一枚硬币i凑成零钱总数j的方案数。

代码如下所示:

public class Solution2 {/*** 找零钱的方案数** @param coins 硬币面值集合* @param total 找的零钱总数* @return 方案数*/public int exchange(int[] coins, int total) {int[][] dp = new int[coins.length + 1][total + 1];for (int i = 0; i <= coins.length; i++) {dp[i][0] = 1;}for (int i = 1; i <= coins.length; i++) {for (int j = 0; j <= total; j++) {dp[i][j] = dp[i-1][j];if (j >= coins[i - 1]) {dp[i][j] += dp[i][j - coins[i - 1]];}}}return dp[coins.length][total];}public static void main(String[] args) {Solution2 solution = new Solution2();int[] coins = new int[]{2, 3, 5};int total = 10;System.out.println(solution.exchange(coins, total));}}

上面是对时间复杂度进行优化,下面对空间进行优化,考虑到dp[i][j]只跟dp[i-1]和dp[i]有关,我们可以把二维降成一维,代码如下所示:

public class Solution3 {/*** 找零钱的方案数** @param coins 硬币面值集合* @param total 找的零钱总数* @return 方案数*/public int exchange(int[] coins, int total) {int[] dp = new int[total + 1];dp[0] = 1;for (int i = 1; i <= coins.length; i++) {for (int j = coins[i - 1]; j <= total; j++) {dp[j] += dp[j - coins[i - 1]];}}return dp[total];}public static void main(String[] args) {Solution3 solution = new Solution3();int[] coins = new int[]{2, 3, 5};int total = 10;System.out.println(solution.exchange(coins, total));}}

五、执行结果

动态规划经典题目-找零钱的方案数相关推荐

  1. 动态规划经典题目-找零钱的最少硬币数

    文章目录 一.题目描述 二.解题思路(朴素版本) 1. 定义状态 2. 定义状态转移方程 3. 初始化 三.代码实现 四.优化 五.执行结果 一.题目描述 ​ 美国的硬币按照面值1, 5, 10, 2 ...

  2. 经典背包问题3——背包问题求方案数 、背包问题求具体方案

    经典背包问题3--背包问题求方案数 .背包问题求具体方案 1. 背包问题求方案数 2. 背包问题求具体方案 1. 背包问题求方案数 有 N 件物品和一个容量是 V的背包.每件物品只能使用一次. 第 i ...

  3. 动态规划经典题目_动态规划经典题目:鸡蛋掉落(附视频讲解)

    题目: 思路: 先放上视频讲解 动态规划经典题目:鸡蛋掉落https://www.zhihu.com/video/1225199247848513536 纠正:视频里的状态转移方程漏写了一个+1,意思 ...

  4. 动态规划经典题目-最小权三角剖分

    文章目录 一.题目描述 二.解题思路 1. 定义状态 2. 定义状态转移方程 3. 初始化 4. 计算方式 三.代码实现 四.执行结果 五.思考 一.题目描述 设A是顶点为0,1,-,n-1的n凸多边 ...

  5. 动态规划经典题目整理

    动态规划经典题目整理 背包问题 最长公共子串问题 连续数组最大和问题 持续增加中.... 背包问题 复杂度 O(nW)O(nW)O(nW) nnn为物品种类,WWW是背包的重量 目的:使得背包中的物品 ...

  6. 动态规划经典题目——最大子矩阵和

    一.题目 题目描述:现给出一个N*N矩阵,要求求出拥有最大和的子矩阵的和.例子如下图所示: 它的最大子矩阵的和为15: 二.解题思路 此题的解法与动态规划经典题目--最大连续子序列之和题目思想一样,只 ...

  7. 动态规划经典题目-数据压缩之图像压缩

    文章目录 一.题目描述 二.解题思路 1. 定义状态 2. 定义状态转移方程 3. 初始化 4. 计算方式 三.代码实现 四.执行结果 五.思考 一.题目描述 ​ 计算机中的图像由一系列像点构成,每个 ...

  8. poj动态规划经典题目

    列表一:经典题目题号: 容易: 1018, 1050, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 1189, 1191,1208, 1276, 1322, 1 ...

  9. 动态规划经典题目——数塔问题

    一.题目 数塔问题 :要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 二.解题思路 动态规划解题思路可详见另一篇文章.数塔中元素用二维数组a[][]表示 ①定义状态 ...

最新文章

  1. 2018 蓝桥杯省赛 B 组模拟赛(一)H.封印之门 最短路
  2. CSS3动画 - 图片开关灯阴影动画
  3. 麻省理工学生令计算机系统升级不需重启
  4. mysql datetime为空不显示_将null和格式不正确的datetime值导入datetime列MySQL
  5. android studio创建9.patch图片,使用时出现Error: Duplicate resources
  6. 最新版2017安装教程
  7. 大数据培训分享大数据六大核心技术
  8. DCDC和LDO原理和关键技术(学习笔记1-buck电路)
  9. ltp测试操作步详解(压力测试网站最详、下载、使用)
  10. 8086汇编段地址和偏移地址分配原则,深入理解.
  11. 平面设计中的对比设计技巧
  12. 如何利用快解析快速实现动态域名解析,内网穿透?
  13. 实习日记 08/23 day33 理解JVM---Java核心卷中的并发
  14. 采访了12位中年程序员,听听他们的故事和人生!
  15. 微信小程序Canvas绘制图案(生成海报、朋友圈海报)
  16. python快速注释html5_python注释代码块
  17. Java匹马行天下之教你用学汉语式方法学编程语言
  18. Windows安裝SourceTree
  19. 筒仓计算表格_小时,速度,筒仓团队和甘特兹
  20. 阿里巴巴大规模神龙裸金属 Kubernetes 集群运维实践

热门文章

  1. JavaScript 生成器函数
  2. APP+spring boot基于Android智能手机的微课程学习系统设计与实现 毕业设计-附源码100909
  3. android view架构,ViewModel 概览
  4. KBE_登录Demo
  5. 记KBE多level使用
  6. GPT-4大模型硬核解读,看完成半个专家
  7. Likely root cause: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes 的解决办法
  8. MKL与VS2019配置方法
  9. 因买不到RTX 3090!他花19万搭了一个专业级机器学习工作站
  10. linux存储池没足够空间,修改群晖存储池及存储空间顺序 | 呉真的博客