动态规划|LeetCode322零钱兑换求最优解

题目:给定不同面额的硬币coins和一个总金额amount,编写一个函数来计算凑成总金额的最少硬币数量,如果没有任何一种硬币可以组成总金额,则返回-1。
在这里插入图片描述
关于硬币问题我们可以有3种思路:

  1. 贪心算法:每次选取面值最大的硬币,但会存在鼠目寸光现象,无法达到最优效果,比如coins=[1,5,11],amount=15,求解amount=111+14,硬币数量为1+4=5(贪心法),但是15=5*3,硬币数量更少
  2. 暴力枚举,未尝试,想想就是for循环嵌套一大堆
  3. 动态规划–DP,特点:最优子结构,无后效性(本次硬币数量求最优解采用动态规划

举个栗子┗|`O′|┛ 嗷~~!
coins=[1,2,3],amonunt=6,F(i)代表总金额为i的硬币数量,分析下面表格:
在这里插入图片描述
我们可以得出规律,总金额为i的最少硬币数量为:
F(i)=min(F(i-coins[j]))+1 //j为0到硬币数量-1
视频学习推荐:https://www.bilibili.com/video/av85797996

附官方解答方法三代码(自行添加的注释),方法实在是妙

public class leet322 {
 public int coinChange(int[] coins, int amount) {
  int max = amount + 1;//数组长度
  int[] dp = new int[amount + 1];//数组初始化
  Arrays.fill(dp, max);//创建数组,数组填充
  dp[0] = 0;//面额为0的最优解为0
  //开始遍历,i和j分别代表dp(i)行数(从1至总金额-1)和面额数量
  for (int i = 1; i <= amount; i++) {
   for (int j = 0; j < coins.length; j++) {
        if (coins[j] <= i) {
         //巧妙之处:每一行的第一个最小值必定为dp[i-coins[j]]+1
         //因为第一个的dp[i]还没有确定,进行一行中的第二个面额求最优解
         //将第一个的dp[i]与第二个的dp[i-coins[j]]+1进行比较
         //依次得出dp[i]的最优解
         dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
           }
         }
       }
  //面额*数量=总金额,那dp[amount]一定小于等于总金额
       return dp[amount] > amount ? -1 : dp[amount];
     }
   }
发布了3 篇原创文章 · 获赞 2 · 访问量 430

猜你喜欢

转载自blog.csdn.net/S_snowxue/article/details/104743877