LeetCode-322.零钱兑换

朱雀 2024-03-25 19:39 194阅读 0赞

目录

    • 题目思路
    • 回溯法
    • 动态规划
    • 动态规划(压缩)

题目来源
322. 零钱兑换

题目思路

1.可以重复选,说明是重复背包问题
2.所以本题并不强调集合是组合还是排列。(建议使用组合好理解)
组合和排列一个是先遍历物品,再遍历重量,另一个是先遍历重量,在遍历物品

回溯法

突破点要定义最大值,因为我们要求最小值

  1. class Solution {
  2. int ans =Integer.MAX_VALUE;
  3. //计算需要几个硬币
  4. int count = 0;
  5. public int coinChange(int[] coins, int amount) {
  6. //根据题目要求amount==0 直接为0
  7. if(coins == null || coins.length < 1 || amount==0){
  8. return 0;
  9. }
  10. backtracking(coins,amount,0,0);
  11. //如果还是最大值,说明没有凑成目标数
  12. if(ans == Integer.MAX_VALUE){
  13. return -1;
  14. }
  15. return ans;
  16. }
  17. private void backtracking(int[] coins,int target,int sum,int startIndex){
  18. if(sum == target){
  19. ans = Math.min(ans,count);
  20. return;
  21. }
  22. //剪枝
  23. if(sum > target){
  24. return;
  25. }
  26. for(int i = startIndex;i<coins.length;i++){
  27. sum += coins[i];
  28. count++;
  29. backtracking(coins,target,sum,i);
  30. sum -= coins[i]; //回溯
  31. count--; //回溯
  32. }
  33. }
  34. }

在这里插入图片描述

动态规划

  1. class Solution {
  2. public int coinChange(int[] coins, int amount) {
  3. if(coins == null || coins.length < 1 || amount == 0){
  4. return 0;
  5. }
  6. int[][] dp = new int[coins.length+1][amount+1];
  7. for(int j = 0; j <= amount; j++){
  8. dp[0][j] = Integer.MAX_VALUE;
  9. }
  10. dp[0][0] = 0;
  11. for(int i = 1;i<=coins.length;i++){
  12. for(int j = 0;j<=amount;j++){
  13. if(j>=coins[i-1] && dp[i][j - coins[i-1]] != Integer.MAX_VALUE){
  14. dp[i][j] = Math.min(dp[i-1][j], dp[i][j - coins[i-1]] + 1);
  15. }else{
  16. dp[i][j] = dp[i-1][j];
  17. }
  18. }
  19. }
  20. if(dp[coins.length][amount] == Integer.MAX_VALUE){
  21. return -1;
  22. }
  23. return dp[coins.length][amount];
  24. }
  25. }

在这里插入图片描述

在这里插入图片描述

动态规划(压缩)

  • 1.确定dp数组以及下标的含义

dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

  • 2.确定递推公式

凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])
所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。
递推公式:dp[j] = Max.min(dp[j - coins[i]] + 1, dp[j]);

  • 3.dp数组如何初始化

首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;

  1. for(int j = 0; j <= amount; j++){
  2. dp[0][j] = Integer.MAX_VALUE;
  3. }
  4. dp[0][0] = 0;
  • 4.确定遍历顺序

本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。
所以本题并不强调集合是组合还是排列。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。

  • 5.举例推导dp数组

在这里插入图片描述
代码实现

  1. class Solution {
  2. public int coinChange(int[] coins, int amount) {
  3. if(coins == null || coins.length < 1 || amount == 0){
  4. return 0;
  5. }
  6. int[] dp = new int[amount+1];
  7. for(int j = 0;j<dp.length;j++){
  8. dp[j] = Integer.MAX_VALUE;
  9. }
  10. dp[0] = 0;
  11. for(int i = 0;i<coins.length;i++){
  12. for(int j = coins[i];j<=amount;j++){
  13. if (dp[j - coins[i]] != Integer.MAX_VALUE) {
  14. //选择硬币数目最小的情况
  15. dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
  16. }
  17. }
  18. }
  19. if(dp[amount] == Integer.MAX_VALUE){
  20. return -1;
  21. }
  22. return dp[amount];
  23. }
  24. }

在这里插入图片描述

发表评论

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

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

相关阅读

    相关 leetcode 322 零钱兑换

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

    相关 leetcode322 零钱兑换

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

    相关 322. 零钱兑换

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

    相关 Leetcode 322. 零钱兑换

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

    相关 LeetCode-322. 零钱兑换

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