美文网首页我爱学习
LeetCode 零钱兑换 背包问题

LeetCode 零钱兑换 背包问题

作者: 燃烧望北斗 | 来源:发表于2020-04-24 15:24 被阅读0次

    题目地址:
    322.零钱兑换 leetcode地址
    518.零钱兑换2 leetcode地址
    类似题目:
    123.股票问题 leetcode地址

    322.零钱兑换

    思路:
    状态转移方程:dp[i]=min(dp[i-coin])+1 coin是coins的元素。
    dp[i]表示凑成总金额i所需的最少的硬币个数。
    状态转移方程的含义是:
    凑成i所需的最少的硬币个数=凑成总金额(i-coin)所需的最少的硬币个数+1。
    比较选出最少的dp[i]。+1表示选择了某个硬币。
    比如,coins={1,2,5},那么dp[i]=min(dp[i-1],dp[i-2],dp[i-5])选出最少的硬币个数。

    class Solution {
        public int coinChange(int[] coins, int amount) {
            int dp[]=new int[amount+1];//凑成i最少硬币数量
            dp[0]=0;//初始化dp
            for(int i=1;i<=amount;i++){
                int nums=-1;//如果不能凑成硬币,dp[i]=-1
                for(int j=0;j<coins.length;j++){
                    int tmp=i-coins[j];
                    if(0<=tmp&&dp[tmp]>=0){
                    //判断dp[tmp]>=0的原因:i-coins[j]不能凑成硬币的话继续下一次循环
                        if (nums==-1) {//第一次循环,dp[tmp]里没有值
                            nums=dp[tmp]+1;
                        }else{
                            nums=Math.min(nums,dp[tmp]+1);
                        }
                    }                 
                }
                dp[i]=nums;
            }
            return dp[amount];
        }
    }
    

    518.零钱兑换

    题目:给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

    例子:
    输入: amount = 5, coins = [1, 2, 5] 输出: 4
    解释: 有四种方式可以凑成总金额:
    5=5
    5=2+2+1
    5=2+1+1+1
    5=1+1+1+1+1
    思路:这道题可以看做完全背包问题。dp[i][v]表示最多i枚硬币组成总金额v的硬币组合数。

    1. 接下来找dp[i][v]与之前的状态的关系。之前的状态有哪些?
      这是个二维数组,状态类型有两种,一个是硬币的状态,一个是总金额的状态。
    2. 硬币的状态有几种?对于v=10的情况,coins ={1,2,5},那么可以是10枚硬币组成10元,也可以9枚硬币组成10元,也可以8枚硬币组成10 元等等,dp[i][10]表示最多i枚硬币组成10的组合数,那么dp[10][10]应该包括dp[9][10]的情况,因为最多10枚硬币组成10元的组合数一定包括最多9枚硬币组成10元的组合数。可以知道,状态转移方程大概是dp[i][v]=dp[i-1][v]+?,这样的形式。硬币的状态只与前一个硬币的状态有关。
    3. 总金额的状态有几种?根据零钱兑换1的思路,可以找一下dp[i][v]与dp[i][v-coin]的关系,即找最多i枚硬币组成总金额v的硬币组合数与最多i枚硬币组成总金额v-coin的硬币组合数的关系,举个例子,v=10,coins ={1,2,5},那么考虑最多10枚硬币组成10元的组合数和最多10枚硬币组成9元、8元、5元的组合数的关系,剩下9元、8元、5元的情况是选择硬币1、2、5之后的情况。
      所以,dp[i][v]=dp[i][v-1]+dp[i][v-2]+dp[i][v-5]+...
      可以知道,dp[i][v]=sum(dp[i][v-coin]) coin属于coins。

    总结可以得到,dp[i][v]=dp[i-1][v]+dp[i][v-coin],coin属于coins。dp[i-1][v]表示第i枚硬币不选,dp[i][v-coin]表示选择第i枚硬币。

    class Solution {
        public int change(int amount, int[] coins) {
            int dp[]=new int[amount+1];
            //dp[i]表示组成总金额i的组合数
            dp[0]=1;
            for(int i=0;i<coins.length;i++){
                for(int j=coins[i];j<amount+1;j++){
                    dp[j]=dp[j]+dp[j-coins[i]];
                }
            }
            return dp[amount];
        }
    }
    
    代码图解

    相关文章

      网友评论

        本文标题:LeetCode 零钱兑换 背包问题

        本文链接:https://www.haomeiwen.com/subject/notfwhtx.html