322. 零钱兑换

难度 中等

给你一个整数数组 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

提示:

题解

​ 看到这道题的时候,有两个想法,背包问题,深搜。因为硬币就是物品,总额就是背包容量。当我没放入一种硬币的时候,减去相应的价值,然后深搜递归继续搜索剩下价值的硬币数量。但是这种办法会超时,因为越是越小价值的总额,调用的次数越频繁,有没有更好的办法解决这个问题呢,那就是记忆搜索法。

记忆搜索法

​ 第一次接触记忆搜索法的时候好像是斐波拉契序列,因为f(n) = f(n-1) + f(n-2),像f(0),f(1)这些会频繁递归调用,这样的效率非常低,所以就有人想出了打表方法,就是把所有可能的斐波拉契序列先求出来,把f(0)换成a[0],f(1)换成a[1],这样调用函数变成去数组元素。

​ 使用背包+深搜的时候,最大的问题就是递归调用过多,我们可以利用空间换时间,把调用函数换成数组。

class Solution {public int coinChange(int[] coins, int amount) {if(amount < 1){//总额小于1,直接返回0return 0;}return coinChange(coins, amount, new int[amount]);}int coinChange(int[] coins, int amount, int[] count){if(amount < 0){//总额小于0,返回-1,表示不能放入这个硬币return -1;}if(amount == 0){//总额为0,表示放入这个硬币之后刚刚好,无须在放入银币return 0;}if(count[amount - 1] != 0){//把递归调用换为数组return count[amount - 1];}int min = Integer.MAX_VALUE;for(int coin : coins){//遍历每个硬币int res = coinChange(coins, amount - coin, count);//递归调用搜索结果集if(res >= 0 && res < min){//返回结果大于等于0,结果需要小于其他枚举的硬币数量侧,才更新最小值min = 1 + res;}}count[amount - 1] = (min == Integer.MAX_VALUE) ? -1 : min;return count[amount - 1];}
}

​ 这个方法时间效率也不是很好,因为给出的数据硬币是升序的,每次枚举都是从小到大进行枚举,我们其实也可以加入贪心算法,对硬币进行降序排序,然后通过剪枝等来降低时间复杂度。

动态规划

​ 其实背包问题就是动态规划,但是记忆搜索法是通过搜索状态来完成状态的转移,这样时间效率上和暴搜没什么区别,我们需要找到动态转移方程才行。

​ 背包问题的动态转移方程是没当遍历到一个物品的时候,看看能不能放进去这个物品,然后在背包里面腾出一个容量为这个物品的地方,再判断当前价值是否增加。(dp[i] = max( dp[i], dp[i - w[j]]))

​ 硬币问题的动态转移方程应该是dp[i] = min( dp[i], dp[i - c[j]]),当放入第i个硬币的时候,看看会不会使硬币数量变小,变小的话就更新状态。

​ 所以状态转移方程为:

  • 当 i = 0时,dp[ i ] = 0
  • 当 i > 0时,dp[ i ] = min(dp[ i - c[ j ] ], dp[ i ])
class Solution {public int coinChange(int[] coins, int amount) {int max = amount + 1;int[] dp = new int[amount + 1];//动态数组Arrays.fill(dp, max);//用最大值填充数组,硬币数量不会超过数组容量 + 1dp[0] = 0;//初始化for(int i = 1; i <= amount; i++){//遍历状态for(int j = 0; j < coins.length; j++){//遍历硬币if(coins[j] <= i){//总额大于硬币面值dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);//动态转移方程}}}return dp[amount] > amount ? -1 : dp[amount];}
}

LeetCode 322. 零钱兑换相关推荐

  1. leetcode: 322.零钱兑换

    322.零钱兑换 来源:力扣(LeetCode) 链接: https://leetcode.cn/problems/coin-change/ 给你一个整数数组 coins ,表示不同面额的硬币:以及一 ...

  2. LeetCode 322. 零钱兑换(DP)

    文章目录 1. 题目信息 2. 解题 2.1 回溯穷举 2.2 动态规划 1. 题目信息 给定不同面额的硬币 coins 和一个总金额 amount. 编写一个函数来计算可以凑成总金额所需的最少的硬币 ...

  3. golang力扣leetcode 322.零钱兑换

    322.零钱兑换 322.零钱兑换 题解 代码 322.零钱兑换 322.零钱兑换 题解 //state: dp[i]金额为i时所需最少硬币个数 //function: dp[i]=dp[i-n]+1 ...

  4. Java实现 LeetCode 322 零钱兑换

    322. 零钱兑换 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: 输 ...

  5. [LeetCode] 322.零钱兑换 五种方法讲解

    322.零钱兑换 五种方法讲解 文章目录 322.零钱兑换 五种方法讲解 1 问题描述 2 问题分析 3 解决策略 3.1 递归-暴力解决 3.2 递归-加入存储 3.3 BFS 3.4 动态规划-自 ...

  6. Leetcode.322 零钱兑换

    索引iii表示 amountamountamount 金额,dp[i]dp[i]dp[i] 表示最少 coinscoinscoins 个数. 递归 class Solution {int res = ...

  7. Leetcode 322.零钱兑换

    Time: 20190906 Type: Medium 题目描述 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币 ...

  8. leetcode 322. 零钱兑换 思考分析

    目录 1.题目 2.思路分析 3.参考链接 1.题目 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总 ...

  9. 99. Leetcode 322. 零钱兑换 (动态规划-完全背包)

    步骤一.确定状态: 确定dp数组及下标含义 dp数组是个amout+1的数组,dp[j]表示的是装满容量为j的背包所需要的最 少物品的个数 步骤二.推断状态方程: 对于当前物品i, 有两种选择决定了d ...

最新文章

  1. java中velocity定义宏标签_velocity自定义标签和指令(转:zwj)
  2. oracle双机python连接_Python连接Oracle
  3. C语言之基本算法26—佩尔方程求解
  4. Python3字符串复制
  5. 软件测试用例优秀例子_功能测试用例设计方法分享
  6. 当互联网人有了孩子后...
  7. Android常用开源框架
  8. 支付宝当前最新版集成2.1.2版本
  9. iPhone 9又要鸽了?
  10. 快照隔离(Snapshot Isolation)简单介绍和例子
  11. python操作注册表能干啥_转 python操作注册表模块_winreg
  12. oracle中使用kill,WINDOWS和LINUX服务器级别的KILLORACLE进行方法
  13. 【转】NB的specify
  14. 英威腾GD200A系列变频器实现多段速控制的相关参数设置及接线
  15. socket.io实现一对多的在线咨询客服系统
  16. Cortana搜索框怎么在任务栏显示?
  17. iOS苹果个人开发者账号购买流程 2018 版
  18. 【数组练习题】计算一下牧场中的草丛数量(详细代码)
  19. 推荐一款超快的Android模拟器
  20. 在Windows7和Ubuntu上编译安装MICO

热门文章

  1. 安卓应用开发期末与面试概念冲刺(概念与代码,from hitwh)
  2. 真无线耳机什么牌子好?高颜值旗舰蓝牙耳机
  3. idea插件安装路径
  4. Java中的二维数组和递归
  5. 2018.7.8随想
  6. matlab求两向量夹角_初学讲义之高中数学十四:向量的数量积
  7. Apache工具类Pair和Triple详解
  8. cadence原理图器件库
  9. css实现折叠样式实现
  10. color from name