zoukankan      html  css  js  c++  java
  • [LeetCode] 322. 零钱兑换 ☆☆☆(动态规划)

    动态规划套路详解

    描述

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

    示例 1:

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

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

    说明:
    你可以认为每种硬币的数量是无限的。

    解析

    这是符合最优子结构的。

    比如你想求 amount = 11 时的最少硬币数(原问题),如果你知道凑出 amount = 10 的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚面值为 1 的硬币)就是原问题的答案,因为硬币的数量是没有限制的,子问题之间没有相互制,是互相独立的。

    思考如何列出正确的状态转移方程

    先确定「状态」,也就是原问题和子问题中变化的变量。由于硬币数量无限,所以唯一的状态就是目标金额 amount

    然后确定 dp 函数的定义:当前的目标金额是 n,至少需要 dp(n) 个硬币凑出该金额。

    然后确定「选择」并择优,也就是对于每个状态,可以做出什么选择改变当前状态。具体到这个问题,无论当的目标金额是多少,选择就是从面额列表 coins 中选择一个硬币,然后目标金额就会减少:

    # 伪码框架
    def coinChange(coins: List[int], amount: int):
        # 定义:要凑出金额 n,至少要 dp(n) 个硬币
        def dp(n):
            # 做选择,选择需要硬币最少的那个结果
            for coin in coins:
                res = min(res, 1 + dp(n - coin))
            return res
        # 我们要求的问题是 dp(amount)
        return dp(amount)

    最后明确 base case,显然目标金额为 0 时,所需硬币数量为 0;当目标金额小于 0 时,无解,返回 -1。

    代码

    int coinChange(int[] coins, int amount) {
            // 数组大小为 amount + 1,初始值也为 amount + 1
            int[] dp = new int[amount + 1];
            for (int i = 0; i < dp.length; i++) {
                dp[i] = amount + 1;//当然这里可以是Integer.MAX_VALUE,只需要下面比较时,取较小值就行。
            }
            // base case
            dp[0] = 0;
            for (int i = 0; i < dp.length; i++) {
                // 内层 for 在求所有子问题 + 1 的最小值
                for (int coin : coins) {
                    // 子问题无解,跳过
                    if (i - coin < 0) continue;
                    dp[i] = Math.min(dp[i], 1 + dp[i - coin]);
                }
            }
            return (dp[amount] == amount + 1) ? -1 : dp[amount];
        }

    PS:为啥 dp 数组初始化为 amount + 1 呢,因为凑成 amount 金额的硬币数最多只可能等于 amount(全用 1 元面值的硬币),所以初始化为 amount + 1 就相当于初始化为正无穷,便于后续取最小值。

  • 相关阅读:
    WHMCS系统API调用
    Zend Guard Loader/Zend Loader是干什么的
    代理IP收集
    Jenkins 2.x版本的节点配置选项更新
    Visual Studio 2015 未响应/已停止工作的问题解决
    Visual Studio多版本进行切换的研究
    商城产品如何应对多个客户不同的需求修改并发布对应客户的文件
    Visual Studio插件
    微软注册dll在dotnet开发时起到缓存的作用
    Visual Studio 2015出现Cannot find one or more components. Please reinstall the application.的问题解决
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/12769506.html
Copyright © 2011-2022 走看看