LeetCode打卡——322.零钱兑换JAVA

LeetCode打卡——322.零钱兑换

题目描述:

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

示例:

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

示例 2:

输入: coins = [2], amount = 3
输出: -1

思路:

涉及到选与不选的问题,很明显可以用动态规划来解,我们可以令result[i][j]来表示仅考虑前i中硬币,且剩余的总金额为j的情况的最优解,接下来寻找状态转移方程。当i=1时,即仅考虑第一个硬币的情况下,问题的解即取决于j是否能整除i。当i>1时,问题的解为不考虑第i中硬币的情况和考虑k个第i种硬币的情况比较后得到的最小值(1<=k<=maxCount,maxCount=j/coins[i]),因此可以得到如下状态转移方程:
r e s u l t [ i ] [ j ] = { m i n { r e s u l t [ i − 1 ] [ j ] , r e s u l t [ i − 1 ] [ j − k ∗ c o i n s [ i ] ] + k } , i>1,k从1取到maxCount j % i = = 0 ? j / i : − 1 , i=1 result[i][j]= \begin{cases} min\{result[i-1][j],result[i-1][j-k*coins[i]]+k\},& \text{i>1,k从1取到maxCount}\\ j\%i==0?j/i:-1,& \text{i=1} \end{cases} result[i][j]={min{result[i1][j],result[i1][jkcoins[i]]+k},j%i==0?j/i:1,i>1,k1取到maxCounti=1

代码:

class Solution {
    public int coinChange(int[] coins, int amount) {
        int sumCount = coins.length;//硬币总数
        int[][] result = new int[sumCount+1][amount+1];//问题的解
        for (int i = 1;i <= sumCount;i++){//初始化j为0的情况下问题的解为0
            result[i][0] = 0;
        }
        for (int j = 1;j <= amount;j++){//初始化i为1的情况
            result[1][j] = j%coins[0] == 0 ? j/coins[0] : -1;
        }
        for (int i = 2;i <= sumCount;i++){
            for (int j = 1;j <= amount;j++){
                result[i][j] = result[i-1][j];//不考虑第i种硬币的情况
                int countI = 1;
                while (j-countI*coins[i-1] >= 0){//考虑第i中硬币的情况下
                    int temp = result[i-1][j-countI*coins[i-1]];
                    if (temp == -1){//判断当前countI的取值是否有解
                        countI++;
                        continue;
                    }
                    temp += countI;//若有解则加上硬币数
                    if (temp < result[i][j] || result[i][j] == -1){
                        //判断该种取法是否小于当前最优解
                        result[i][j] = temp;
                    }
                    countI++;
                }
            }
        }
        return result[sumCount][amount];
    }
}

优化:

在这里插入图片描述

代码提交后通过了,但效率并不是很高,算法一共有三层循环,外两层循环分别取决于硬币数量和总金额,而第三层循环则取决于每枚硬币的面值,我们可以通过将问题result[i][j]转化为result[i][j-coins[i]]+1来删去该层循环,优化后的状态转移方程为:
r e s u l t [ i ] [ j ] = { m i n { r e s u l t [ i − 1 ] [ j ] , r e s u l t [ i ] [ j − c o i n s [ i ] ] + 1 } , i>1 j % i = = 0 ? j / i : − 1 , i=1 result[i][j]= \begin{cases} min\{result[i-1][j],result[i][j-coins[i]]+1\},& \text{i>1}\\ j\%i==0?j/i:-1,& \text{i=1} \end{cases} result[i][j]={min{result[i1][j],result[i][jcoins[i]]+1},j%i==0?j/i:1,i>1i=1
代码如下:

class Solution {
    public int coinChange(int[] coins, int amount) {
        int sumCount = coins.length;//硬币总数
        int[][] result = new int[sumCount+1][amount+1];//问题的解
        for (int i = 1;i <= sumCount;i++){//初始化j为0的情况下问题的解为0
            result[i][0] = 0;
        }
        for (int j = 1;j <= amount;j++){//初始化i为1的情况
            result[1][j] = j%coins[0] == 0 ? j/coins[0] : -1;
        }
        for (int i = 2;i <= sumCount;i++){
            for (int j = 1;j <= amount;j++){
                result[i][j] = result[i-1][j];//不考虑第i种硬币的情况
                int countI = 1;
                if (j - coins[i-1] < 0){
                    continue;
                }
                int temp = result[i][j-coins[i-1]];//考虑取一枚第i中硬币
                if (temp == -1){//判断是否有解
                    continue;
                }
                temp++;
                if (temp < result[i][j] || result[i][j] == -1){
                    result[i][j] = temp;//比较去最小值
                }
            }
        }
        return result[sumCount][amount];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值