322.零钱兑换(动态规划和贪心)

322. 零钱兑换#

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

基本是按照这篇题解的思路

贪心
11. 想要总硬币数最少,肯定是优先用大面值硬币,所以对 coins 按从大到小排序
12. 先丢大硬币,再丢会超过总额时,就可以递归下一层丢的是稍小面值的硬币

乘法对加法的加速
21. 优先丢大硬币进去尝试,也没必要一个一个丢,可以用乘法算一下最多能丢几个

k = amount / coins[c_index] 计算最大能投几个
amount - k * coins[c_index] 减去扔了 k 个硬币
count + k 加 k 个硬币

如果因为丢多了导致最后无法凑出总额,再回溯减少大硬币数量

最先找到的并不是最优解
31. 注意不是现实中发行的硬币,面值组合规划合理,会有奇葩情况
32. 考虑到有 [1,7,10] 这种用例,按照贪心思路 10 + 1 + 1 + 1 + 1 会比 7 + 7 更早找到
33. 所以还是需要把所有情况都递归完

ans 疯狂剪枝
41. 贪心虽然得不到最优解,但也不是没用的
42. 我们快速算出一个贪心的 ans 之后,虽然还会有奇葩情况,但是绝大部分普通情况就可以疯狂剪枝了

作者:ikaruga
链接:https://leetcode-cn.com/problems/coin-change/solution/322-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    private int min=Integer.MAX_VALUE;
    public int coinChange(int[] coins, int amount) {
        if(coins==null||coins.length==0)
            return -1;
        Arrays.sort(coins);
        helper(coins,0,coins.length-1,amount);
        return min==Integer.MAX_VALUE?-1:min;
    }
    public void helper(int[] coins,int res,int index,int all)
    {
        if(all==0)
        {
            min=Math.min(res,min);
            return ;
        }
        if(index<0) //说明这种移动不能得到一个有效值,所以直接返回。
            return;
        for(int i=all/coins[index];i>=0&&res+i<min;i--) //这里i取到0就会跳到下一个位置,就可以在最上层实现移动。
        {
            helper(coins,res+i,index-1,all-i*coins[index]);
        }
    }
}

使用dp来做,让amount从小到大增加,使得后面的dp值复用前面的

class Solution {
    public int coinChange(int[] coins, int amount) {
        if(coins==null||coins.length==0)
            return -1;
       int[] dp=new int[amount+1];
       for(int i=1;i<dp.length;i++)
            dp[i]=Integer.MAX_VALUE;
       for(int i=1;i<=amount;i++)
       {
           int min=Integer.MAX_VALUE;
           for(int j=0;j<coins.length;j++)
           {
               if(i-coins[j]>=0&&(dp[i-coins[j]]!=Integer.MAX_VALUE))
                    min=Math.min(dp[i-coins[j]]+1,min);
           } 
           dp[i]=min; 
       }

       return dp[amount]==Integer.MAX_VALUE?-1:dp[amount];
    }
 
}
原文地址:https://www.cnblogs.com/cold-windy/p/12444427.html