题目
(322). 零钱兑换
题目描述
给定不同面额的硬币coins和一个总金额amount;编写一个函数来计算可以凑成总金额所需的最少的硬币个数;如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
示例
示例一
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例二
输入:coins = [2], amount = 3
输出:-1
思路
明确base case -> 明确【状态】 -> 明确【选择】 -> 定义DP数组/函数的含义
base case:amount=0,则返回0,不需要任何硬币就满足条件
状态:amount的逐渐先base case靠近,原问题与子问题中变化的量
选择:导致状态发生变化的行为,选择一枚硬币,状态(amount)就会变化
定义DP函数/数组的含义:输入一个目标金额n,返回凑出目标金额n的最少硬币数量。
代码
package leetcode
import "log"
// coinChange
// 零钱兑换
// stack overflow
func coinChange(coins []int, amount int) int {
// 求最小值,所以初始化为正无穷
maxInt := 1<<31 - 1
var dp func(amount int) int
dp = func(amount int) int {
if amount == 0 {
return 0
}
if amount < 0 {
return -1
}
num := maxInt
// [1, 2, 5]
// 11
for _, coin := range coins {
// 子问题
subProblem := dp(amount - coin)
if subProblem == -1 {
continue
}
num = min(num, 1+subProblem)
}
if num == maxInt {
return -1
} else {
return num
}
}
return dp(amount)
}
// min
// 获取两个整型最小值
func min(a, b int) int {
if a > b {
return b
}
return a
}
// coinChange
// 零钱兑换
// 通过备忘录解决重叠子问题
func coinChangeV2(coins []int, amount int) int {
// 求最小值,所以初始化为正无穷
maxInt := 1<<31 - 1
data := map[int]int{}
var dp func(amount int) int
dp = func(amount int) int {
// 从备忘录中获取
if _, ok := data[amount]; ok {
return data[amount]
}
if amount == 0 {
return 0
}
if amount < 0 {
return -1
}
num := maxInt
// [1, 2, 5]
// 11
for _, coin := range coins {
// 子问题
subProblem := dp(amount - coin)
if subProblem == -1 {
continue
}
num = min(num, 1+subProblem)
}
if num == maxInt {
data[amount] = -1
} else {
data[amount] = num
}
return data[amount]
}
return dp(amount)
}
// coinChange
// 零钱兑换
// 通过备DP table解决重叠子问题
// 超出时间限制
func coinChangeV3(coins []int, amount int) int {
// dp := make([]int, amount+1)
dp := map[int]int{}
// base case
dp[0] = 0
number := amount + 1
// 外层for循环在遍历所有状态的所有取值
// [2,5,10,1] 27
for i := 0; i < number; i++ {
// 内层for缓存在求所有选择的最小值
for _, coin := range coins {
// 子问题无解
if (i - coin) < 0 {
continue
}
// 设置默认值
if _, ok := dp[i]; !ok {
dp[i] = number
}
if _, ok := dp[i-coin]; ok {
dp[i] = min(dp[i], 1+dp[i-coin])
}
log.Println(i, dp[i])
}
}
if rs, ok := dp[amount]; !ok || rs == number {
return -1
} else {
return dp[amount]
}
}
leetcode提交记录
参考
来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/co…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。