322. 零钱兑换

╰半夏微凉° 2023-07-13 05:57 130阅读 0赞

题目:

322. 零钱兑换
在这里插入图片描述

题解:动态规划

1. 解释一:

在这里插入图片描述
在这里插入图片描述

2. 解释二:

在这里插入图片描述

3. 解释三:

  1. 动态规划:尝试分解子问题
  2. - 在研究了好几天,看了大佬们无数的解题思想之后,我终于明白了动态规划的本质,其实理解
  3. 一个算法的思想,有很多时候只差临门一脚,希望我的题解能帮助到大家。
  4. - 我们经常听到「最优子结构」「缩小问题规模」「自顶向下」「自底向上」等跟动态规划
  5. 相关的词汇。
  6. - 接下来就彻底搞懂这种思想,顺带着我自己也重温一遍刚刚搞懂的喜悦。
  7. ----------------开始解题,拿实例来说话----------------------
  8. - 假设给出的不同面额的硬币是[1, 2, 5],目标是 120,问最少需要的硬币个数?
  9. - 我们要分解子问题,分层级找最优子结构,看到这又要晕了哈,憋急~~ 下面马上举例。
  10. - 这里我们使用「自顶向下」思想来考虑这个题目,然后用「自底向上」的方法来解题,
  11. 体验算法的冰火两重天。
  12. - dp[i]: 表示总金额为 i 的时候最优解法的硬币数
  13. - 我们想一下:求总金额 120 有几种方法?下面这个思路关键了 !!!
  14. 一共有 3 种方式,因为我们有 3 种不同面值的硬币。
  15. 1.拿一枚面值为 1 的硬币 + 总金额为 119 的最优解法的硬币数量
  16. 这里我们只需要假设总金额为 119 的最优解法的硬币数有人已经帮我们算好了,
  17. 不需要纠结于此。(虽然一会也是我们自己算,哈哈)
  18. 即:dp[119] + 1
  19. 2.拿一枚面值为 2 的硬币 + 总金额为 118 的最优解法的硬币数
  20. 这里我们只需要假设总金额为 118 的最优解法的硬币数有人已经帮我们算好了
  21. 即:dp[118] + 1
  22. 3.拿一枚面值为 5 的硬币 + 总金额为 115 的最优解法的硬币数
  23. 这里我们只需要假设总金额为 115 的最优解法的硬币数有人已经帮我们算好了
  24. 即:dp[115] + 1
  25. - 所以,总金额为 120 的最优解法就是上面这三种解法中最优的一种,也就是硬币数最少
  26. 的一种,我们下面试着用代码来表示一下:
  27. - dp[120] = Math.min(dp[119] + 1, dp[118] + 1, dp[115] + 1);
  28. - 推导出「状态转移方程」:
  29. dp[i] = Math.min(dp[i - coin] + 1, dp[i - coin] + 1, ...)
  30. 其中 coin 有多少种可能,我们就需要比较多少次,那么我们到底需要比较多少次呢?
  31. 当然是 coins 数组中有几种不同面值的硬币,就是多少次了~ 遍历 coins 数组,
  32. 分别去对比即可
  33. - 上面方程中的 dp[119],dp[118],dp[115] 我们继续用这种思想去分解,
  34. 这就是动态规划了,把这种思想,思考问题的方式理解了,这一类型的题目
  35. 问题都不会太大。

4. 解释四:

在这里插入图片描述

代码:动态规划

  1. /** * code322 */
  2. public class code322 {
  3. public static int coinChange(int[] coins, int amount) {
  4. int max = 100000000; // 一亿
  5. // dp[i] 保存金额 i 的最小组成数
  6. int dp[] = new int[amount + 1];
  7. for (int i = 0; i < dp.length; i++) {
  8. dp[i] = max;
  9. }
  10. dp[0] = 0;
  11. for (int i = 1; i <= amount; i++) {
  12. for (int j = 0; j < coins.length; j++) {
  13. if (coins[j] <= i) {
  14. dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
  15. }
  16. }
  17. }
  18. if (dp[amount] > amount) {
  19. return -1;
  20. } else {
  21. return dp[amount];
  22. }
  23. }
  24. public static void main(String[] args) {
  25. int coins1[] = { 1, 2, 5 };
  26. int amount1 = 11;
  27. int ans1 = coinChange(coins1, amount1);
  28. System.out.println(ans1);
  29. int coins2[] = { 2 };
  30. int amount2 = 3;
  31. int ans2 = coinChange(coins2, amount2);
  32. System.out.println(ans2);
  33. }
  34. }

参考:

  1. 322. 零钱兑换
  2. 自底向上动态规划
  3. 【零钱兑换】贪心 + dfs = 8ms
  4. Java 递归、记忆化搜索、动态规划
  5. 动态规划套路详解
  6. DFS + 剪枝 2ms 击败100%,比 DP 还快?
  7. 动态规划、使用「完全背包」问题思路、图的广度优先遍历
  8. 用背包问题思想来理解硬币找零系列问题
  9. 动态规划算法思想
  10. “一遍就懂之背包问题”
  11. 【动态规划】Python 题解
  12. js 详解动态规划的思想 一步到位
  13. 记忆化回溯 + 动态规划,逐行解释 (Python 3)

发表评论

表情:
评论列表 (有 0 条评论,130人围观)

还没有评论,来说两句吧...

相关阅读

    相关 322. 零钱兑换

    > 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 >

    相关 Leetcode 322. 零钱兑换

    题目重述 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何

    相关 LeetCode-322. 零钱兑换

    [322. 零钱兑换][322.] 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币

    相关 322.零钱兑换

    //给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 // -1