vlambda博客
学习文章列表

算法动态规划(七)-背包问题4

⚠️今天继续我们来探讨背包问题中的完全背包问题。
0-1背包:N个物品,容量为V,每个物品可以无限次使用,求达到V的最值。

👉👀💬 今日练习(一 零钱兑换 (LeetCode-322)。给定一批硬币coins数组,每个硬币可以不限次数使用,求凑成总金额V至少需要多少个硬币。找不到输出-1。 举例:
输入:[1,2,5] , 11输出:3。1+5+5=11
输入:[2],3输出:-1

🙋解法一:记忆化递归

🙇思路:

总体思路就是用coins中的每个数去凑总金额amount,用总金额减去使用过的数,直到amount小等于0退出递归。当amount==0,说明刚刚好凑齐。退出递归。
使用一个map来保存递归中产生的零钱值,减少重复递归。
Map<Integer,Integer> map = new HashMap<>(); public int coinChange(int[] coins, int amount) { if(amount <= 0){ return 0; } return find_h(coins,amount); } private int find_h(int[] nums,int amount){ if(amount <0){ return -1; } if(amount == 0){ return 0; } if(map.containsKey(amount)){ return map.get(amount); } int count=Integer.MAX_VALUE; for(int num:nums){ if(num > amount){ continue; } int solu=find_h(nums,amount-num); if(solu>=0){ count = Math.min(count,solu+1); }        } if(count == Integer.MAX_VALUE){ count =-1; } map.put(amount,count); return map.get(amount); }

🙋解法二:动态规划【自上而下】

🙇思路:

状态定义F(S),凑齐总金额S,需要的最小硬币数。

状态转移方程F(S) = F(S-coins[i]) + 1。

public int coinChange(int[] coins, int amount) { if (amount < 1) return 0; return coinChange_h(coins, amount,new int[amount+1]);}private int coinChange_h(int[] coins, int amount,int[] count) { if (amount < 0) return -1; if (amount == 0) return 0; if (count[amount] != 0) return count[amount]; int min = Integer.MAX_VALUE; for (int coin : coins) { int res = coinChange_h(coins, amount - coin,count); if (res >= 0 ) min = Math.min(1 + res,min); } count[amount] = min == Integer.MAX_VALUE ? -1:min; return count[amount];}

🙋解法三:动态规划【自下而上】

🙇思路:

状态定义:dp[j],凑齐总金额j,需要的最小硬币数。

状态转移方程:dp[i][j]= min(dp[i][j],dp[i](j-coins[i]) + 1)。凑齐总金额j需要的最小硬币数,当地i个硬币选或者不选两种情况。

public int coinChange_2(int[] coins, int amount) { if (amount < 1) return 0; int[] dp = new int[amount+1]; Arrays.fill(dp,amount+1); //这儿解释下为啥默认填充amount+1,凑齐amount最多也就是面值为1的数总计用amount个, // 所以最少个数一定是<amount+1的 dp[0]=0; for(int j=1;j<=amount;j++){ for(int num:coins){ if(num <= j){ dp[j]=Math.min(dp[j],dp[j-num]+1); } } } return dp[amount]==amount+1?-1:dp[amount];}

复杂度分析

  • 时间复杂度:O(SN):这里S是总金额,N是提供的不同面额数,即数组长度。我们要计算O(S)个不同总金额,对每次的总金额需要N个面额来转移状态,一共需要O(SN)的时间复杂度

  • 空间复杂度:O(S),我们使用了一个S+1的dp数组



算法动态规划(七)-背包问题4不积跬步,无以至千里。

文章有帮助的话,点个转发、在看呗算法动态规划(七)-背包问题4

谢谢支持哟 (*^__^*)

END


算法动态规划(七)-背包问题4👇