【LeetCode每周算法】零钱兑换
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0
示例 4:
输入:coins = [1], amount = 1
输出:1
示例 5:
输入:coins = [1], amount = 2
输出:2
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
分析
一些分析内容,借鉴自博客:https://juejin.cn/post/6985150114134229022
怎么感觉像是回到了小学应用题?
1、暴力穷举逐个排除
简单分析一下: 最小硬币组合 -> 尽量用大的硬币
这傻不拉几的题谁出的,这么简单
7+7+7=21,21+2+2+2=27, 6枚硬币
卧槽
7+5+5+5+5=27, 5枚硬币
我们可以很暴力的想一想,从大往小的算,可以加起来不超过27,比如
7+7+7+7 > 27 (排除)
7+7+7+5 或者 7 +7 +7+2+2+2 6枚
....
穷举太慢了,还会涉及到很多的重复计算,如果我想要27以内的任何值最小的硬币组合呢,想想都头大了吧。
既然计算机可以通过内存保存之前的内容,又快,很明显,我们开一个数组来保存之前的状态。
2.动态规划分析
虽然我们不知道最优策略是什么,但是最优策略肯定是K枚硬币,a1, a2, ....ak面值加起来是27
所以一定有一枚最后的硬币:ak. 除掉这么硬币,前面硬币的面值加起来是27-ak
关键点1:
- 我们不关心前面的k-1枚硬币是怎么拼出27-ak的(可能有一种拼法,也可能有100种拼法),而且我们现在甚至还不知道ak和K, 但是我们确定前面的硬币拼出了27-ak
关键点2:
- 因为是最优策略, 所以拼出27-ak的硬币数一定要最少,否则这就不是最优策略了
子问题
- 所以我们就要求:最少用多少枚硬币可以拼出27-ak
- 原问题是最少用多少枚硬币拼出27
- 我们将原问题转化了一个子问题,而且规模更小:27-ak
- 为了简化定义, 我们设状态f(x)=最少用多少枚硬币拼出x
等等,我们还不知道最后的那枚硬币ak是多少
- 很明显,最后的那枚硬币只能是2,5或者7
- 如果ak是2, f(27)应该是f(27-2)+1(1代表最后一枚硬币2)
- 如果ak是5, f(27)应该是f(27-5)+1(1代表最后一枚硬币5)
- 如果ak是7, f(27)应该是f(27-7)+1(1代表最后一枚硬币7)
所以使用最少的硬币数=f(27) = min{f(27-2)+1, f(27-5)+1, f(27-7)+1}
2.1递归解法
private static Map<Integer, Integer> cache = new HashMap<>();static {// 退出条件cache.put(2, 1);cache.put(3, -1);cache.put(4, 2);cache.put(5, 1);cache.put(6, 3);cache.put(7, 1);}// 2,5,7三种硬币public static int minCoin(int target) {if (target < 2) {return -1;}Integer integer = cache.get(target);if (integer != null) {return integer;}// if (target == 2) {
// return 1;
// }
// if (target == 3) {
// return -1;
// }
// if (target == 4) {
// return 2;
// }
// if (target == 5) {
// return 1;
// }
// if (target == 6) {
// return 3;
// }
// if (target == 7) {
// return 1;
// }int[] result = {minCoin(target - 2) + 1,minCoin(target - 5) + 1,minCoin(target - 7) + 1};int min = min(result);cache.put(target, min);return min;}public static int min(int[] valArr) {if (valArr == null || valArr.length < 1) {return Integer.MIN_VALUE;}int val = Integer.MIN_VALUE;for (int i : valArr) {if (i > 0) {val = val > 0 ? Math.min(val, i) : i;}}return val;}
2.2动态规划
转移方程:
- 设状态f(x)=最少用多少枚硬币拼出x
- 对于任意的x : f(X) = min{f(X-2)+1, f(X-5)+1, f(X-7)+1}
初始条件和边界情况:
- 提出问题
- x-2, x-5, x-7 小于0怎么办?
- 什么时候停下来?
如果不能拼出Y, 就定义f[Y] = 正无穷
例如f[-1], f[-2] = 正无穷
例如:拼不出f[1]=min{f(-1)+1, f(-3)+1, f(-6)+1}
初始条件:f[0] = 0
计算顺序
计算:f[1], f[2], ... f[27]
当我们计算到f[x], f[x-2], f[x-5], f[x-7] 都已经得到结果了。如图:
上图7只需要一个硬币。
f[x] = 最少用多少枚硬币拼出x
f[x] = ∞ 表示无法用硬币拼出x
public static int coinChange(int [] A, int M ) {int[] f = new int[M+1];int n = A.length;f[0] = 0;int i,j;for (i = 1; i<=M; i++) {f[i] = Integer.MAX_VALUE;for (j = 0; j< n;j++) {// 边界条件判断if (i >= A[j] && f[i - A[j]] != Integer.MAX_VALUE) {f[i] = Math.min(f[i - A[j]] + 1, f[i]);// System.out.println(i + "=" +f[i]);}}}if (f[M] == Integer.MAX_VALUE) {f[M] = -1 ;}return f[M];
}
【LeetCode每周算法】零钱兑换相关推荐
- LeetCode:322. 零钱兑换(python)
LeetCode:322. 零钱兑换(python) 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总 ...
- 算法------零钱兑换(Java版本)
题目 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1.示例 1:输入: coins ...
- 【LeetCode每周算法】两数相加
题目来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/add-two-numbers 给你两个 非空 的链表,表示两个非负的整数.它们每位数字都是 ...
- JavaScript算法 — 零钱兑换问题
一.问题 二.分析 背包问题. 构造一个初始全是最大值的一维数组dp,dp[i]就代表兑换i元所需要的最少硬币个数. 所以有:dp[i] = Math.min(dp[i], dp[i - j] + 1 ...
- 【LeetCode】322. 零钱兑换 结题报告 (C++)
原题地址:https://leetcode-cn.com/problems/coin-change/ 题目描述: 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成 ...
- leetcode动态规划之零钱兑换问题
给定不同面额的硬币和一个总金额.写出函数来计算可以凑成总金额的硬币组合数.假设每一种面额的硬币有无限个. 输入: amount = 5, coins = [1, 2, 5] 输出: 4 解释: 有四种 ...
- leetcode 322: 零钱兑换
题目描述: 给你一个整数数组 coins ,表示不同面额的硬币:以及一个整数 amount ,表示总金额. 计算并返回可以凑成总金额所需的 最少的硬币个数 .如果没有任何一种硬币组合能组成总金额,返回 ...
- 【必备算法】动态规划:LeetCode题(六)322. 零钱兑换,518. 零钱兑换 II
322. 零钱兑换² 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: ...
- 动态规划——零钱兑换(Leetcode 322)
题目选自Leetcode 322.零钱兑换 想必大家看一眼就明白了(bushi),这就是动态规划的背包问题~ 算法思想 那么,既然知道了这是个动态规划问题,就要思考如何列出正确的状态转移方程? 1.确 ...
最新文章
- 福利 | NVIDIA英伟达免费直播课:带你选择、搭建AI服务器!
- JUnit单元测试用例
- uni-app 修改富文本信息中的图片样式
- Scala语言整理(一)
- Oracle教程之oracle 给用户授权
- 前端学习(1716):前端系列javascript之页面配置下
- oracle实验七 答案,Oracle表的常用查询实验(七)
- C#获取当前堆栈的各调用方法列表
- ROOBO公布A轮1亿美元融资 发布人工智能机器人系统
- 【信号与系统】学习记录1——1.1信号的分类
- 微信 0day漏洞复现
- Excel怎么忽略位置对比两列数据是否相同
- 图像增强(对数,指数,曝光,马赛克)
- SoftIce基础入门
- 物品分类游戏html5,幼儿物品分类教案
- hourglass pytorch 实现
- java编写一个学生类和教师类_JAVA:1、编写一个学生类,类名为Student,包含如下成员:...
- 脑电必读文章:ERP经典成分汇总
- 便携式激励vs形式化vsUVM验证方法在IP块的整个生命周期中的比较分析
- linux命令查看删除哪些文件,linux删除文件除命令有哪些
热门文章
- 神经网络入门-MLP, RNN, BiRNN
- 新手第四课-PaddlePaddle快速入门
- 家里宽带628连不上_连不上无线网络?到底是路由器还是电脑的“锅”,看完这篇就知道...
- python 语言教程(3)变量之字符串
- 微众WeCross 跨链平台(11)系统总结
- C++ Primer 5th笔记(chap 15 OOP)抽象基类
- 深度探索C++ 对象模型(7)-Data member的布局(多重继承)
- 【Flask】数据的CRUD操作之聚合函数
- Linux Kernel 5.10 aarch64体系对TTBR寄存器的设置
- 武汉理工大学软件质量保证与测试,材料测试技术(武汉理工大材料测试技术(武汉理工大学).pdf...