力扣经典算法篇-52-零钱兑换(动态规划)

发布于:2025-08-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

1、题干

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。

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

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

示例 3:
输入:coins = [1], amount = 0
输出:0

提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104

2、解题

方法一:(动态规划)

本题为求取最优值的问题,可以使用贪心或动态规划的算法策略。对于本题,贪心无法获取全局最优的结果,需要使用动态规划的思路。

动态规划的步骤:
1、定义数组
2、初始化赋值
3、找规律
4、对之后的元素赋值
5、最后的元素为结果

规律:
要对一个新的值,要校验这组硬币能否满足组合目标价值的情形,需要遍历这个硬币的集合。
校验某一个硬币时,需要减去当前硬币的价值,验证减去后的值是否满足调价,如果满足条件,该硬币需要校验,否则直接跳过。

代码示例:

import java.util.Arrays;

public class Test60 {

    public static int coinChange(int[] coins, int amount) {
        // 定义数组
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        
        // 初始化赋值
        dp[0] = 0;
        
        // 遍历,后续数据进行赋值
        for (int i = 1; i < amount + 1; i++) {
            // 遍历硬币的列表,验证每一种可能情况,注意不能截断
            for (int j = 0; j < coins.length; j++) {
                int coinValue = coins[j];
                if (coinValue == i) {
                    // 如果等值,只要1个硬币即可,快速截断
                    dp[i] = 1;
                    break;
                } else if (coinValue < i) {  //  只有当硬币价值小于总价值时,才存在逻辑可能,进行校验。
                    // 减去当前硬币价值时,如果存在值,则可以存在结果
                    if (dp[i - coinValue] != Integer.MAX_VALUE) {
                        // 因为10元可以由2个5元拼凑,也可以由10个1元拼凑,所以需要遍历每一种组合的可能,并取较小值
                        dp[i] = Math.min(dp[i], dp[i - coinValue] + 1);
                    }
                }
            }
        }

        // Integer.MAX_VALUE为不可能的情况,注意
        return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
    }

    public static void main(String[] args) {
        int[] coins = {1, 2, 5};
        int amount = 11;
        System.out.println(coinChange(coins, amount));
    }
}

向阳前行,Dare To Be!!!


网站公告

今日签到

点亮在社区的每一天
去签到