【举一反三】力扣刷题-零钱兑换(Go 实现)

快速通道

322. 零钱兑换
518. 零钱兑换 II

前言

这个月是动态规划月呀,动态规划的题目核心就是找到状态转移方程。零钱兑换这个系列是很经典的背包题,就是总容量,然后往里边放固定大小的物品,有的是返回方案数,有的是返回最少物品的个数。

一定要看

一篇文章吃透背包问题!(细致引入+解题模板+例题分析+代码呈现)

322. 零钱兑换

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

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

来源:力扣(LeetCode)

理解

这种题目乍一看很像贪心算法题,先取大的放,不过不行再放小的。不过如果不能正好放下的话,就需要再取小一点的,然后再放重复。这样就类似于回溯算法了,不过这样做执行会超时。
既然超时了,一般回溯(DFS)的做法就是记忆化存储,就是疯狂剪枝。
不过这边就不这样做了,熟悉这种题型的就能判断该题就是背包问题中返回最小物品的个数。

解题

动态规划题型一般都需要一个数组来存储前面的数,然后通过状态转移方程来获取下一个数

func coinChange(coins []int, amount int) int {
    // 背包问题·
    dp := make([]int, amount+1)
    
    for i:=1; i<=amount; i++ {
        dp[i] = amount + 1
        for _, coin := range coins {
            if i >= coin && dp[i - coin] + 1 < dp[i] {
                dp[i] = dp[i - coin] + 1 
            }
        }
    }
    if dp[amount] == amount + 1 {
        return -1
    }
    return dp[amount]
}
518. 零钱兑换 II

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

来源:力扣(LeetCode)

理解

这一题跟之前做过的 377. 组合总和 Ⅳ 很相似 -->
【举一反三】力扣刷题-组合总和(Python 实现)当时这边还是用的回溯+剪枝做的,回头再看看。
说回这一题,这一题也是求组合数,只不过这一题不能有重复的组合,或者说那一题是有序的,所以可以存在重复的组合。

解题

如何保证没有重复的组合呢,那就想办法让组合是单调递增即可,这个地方实现起来稍微麻烦,我要保证我的下一个数不比前一个数小,那我应该让小的数先排。 看实现,先循环的coins,然后再维护dp数组,这个地方很巧妙。开头我放一下力扣上一位大佬写的总结,这位大佬总结了各种背包问题。

func change(amount int, coins []int) int {
    // 动态规划
    dp := make([]int, amount + 1)
    dp[0] = 1
    for _,coin := range coins {
        for i:=coin;i<=amount;i++ {
            dp[i] += dp[i - coin]
        }
    }
    return dp[amount]
}
小试牛刀

279. 完全平方数

讲解:

【知识迁移】力扣刷题- 完全平方数(Go 实现)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值