题解 | #兑换零钱(一)#

兑换零钱(一)

https://www.nowcoder.com/practice/3911a20b3f8743058214ceaa099eeb45

背包问题

此题可视为背包问题,要兑换的钱数aim为背包容量,arr为各个物品的价值,最少需要arr中的几件物品才能装满背包。

如何转换为动态规划思路:DP数组应该存放什么?

题目要求的是最少需要多少张arr中的货币才能组成aim的钱数,可以自顶向下分析,组成aim-1的钱数最少需要多少张货币,... ,组成1的钱数需要多少张货币,组成0的钱数需要多少张货币。这样DP数组中存放的就是组成0-aim的目标钱数最少需要的货币数量。

最小子问题

  • 可以从最简单的情况考虑,如果目标钱数是0,那么组成0的钱数需要0张货币,后面的钱数的最小货币数量都可以通过这个情况由小到大递推得到。
  • 其次可以考虑特殊情况,比如但目标钱数和arr中的纸币金额一致时,只需要1张该金额的货币就可以组成该目标钱数。假设目标钱数为i,arr[j]对应的金额和i相等,此时拿出一张arr[j]组成目标钱数后,还剩下i-arr[j]=0的目标钱数,那剩下的目标钱数最少能兑换多少张纸币呢,即为dp[i-arr[j]=dp[0]=0,那么dp[i]能最少兑换的纸币数量等于一张arr[j]纸币加上dp[i-arr[j]]中最少能兑换的纸币数量,此时dp[i]=1+dp[i-arr[j]]=1。

如何思考状态转移方程?

要组成一个目标钱数为i的纸币,可以分析一下从arr中取出一张金额小于目标钱数i的纸币后,剩下的目标钱数还能兑换的最少纸币数量的情况。对于arr中不同的选取金额的情况,选出最小的一个,即为目标钱数为i的纸币所能得到的最少纸币数量,即dp[i] = min(dp[i-arr[j]], dp[i]),其中arr[j]小于i,且j在arr的金额种类数量范围内。

参考

https://www.bilibili.com/video/BV1cT4y1w7Ct/?spm_id_from=333.880.my_history.page.click

/**
 * 最少货币数
 * @param arr int整型一维数组 the array
 * @param aim int整型 the target
 * @return int整型
 */
function minMoney( arr ,  aim ) {
    // write code here
    const dp = new Array(aim+1).fill(Infinity);  // dp存放目标钱数从0-aim分别最少可以兑换多少张arr中的纸币
    dp[0] = 0;  // 当目标钱数为0时,没有纸币可以兑换,可以兑换的纸币数量为0,根据这个初始状态递推到最终aim金额的所能兑换的最少纸币数量

    for (let i = 1; i <= aim; ++i) {
        // 对于目标钱数为i的背包,分别遍历各个物品,看哪个物品放入后可以塞满i的背包的物品数量最少
        for (let j = 0; j < arr.length; ++j) {
            if (arr[j] <= i) {  // 只有在arr[j]的面额小于等于目标钱数i时,才可以兑换一张arr[j]
                // dp[i-arr[j]]表示i的容量兑换完一张arr[j]的纸币后,剩下的目标钱数最少能兑换的纸币数量,+1表示一张arr[j]
                dp[i] = Math.min(dp[i], dp[i-arr[j]]+1);
            }
        }
    }

    // 遍历完成后,如果aim的目标钱数能够被arr中的所有纸币兑换,则dp[aim]会被更新,否则就是最大值,表示无法被兑换
    return dp[aim] === Infinity ? -1 : dp[aim];
}
module.exports = {
    minMoney : minMoney
};

全部评论

相关推荐

点赞 评论 收藏
分享
09-27 18:15
门头沟学院 C++
在努力的小牛:来告诉你 录用评估挂就是同期好几个候选人,部门负责人选了其他人。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务