题目:
算法:
方法一:搜索
一次找一颗硬币,该方法会超时
var ans = math.MaxInt32
func coinChange(coins []int, amount int) int {
ans = math.MaxInt32
find(coins, amount, 0)
if ans == math.MaxInt32 {
return -1
}
return ans
}
func find(coins []int, amount, cnt int) {
if amount < 0 {
return
}
if amount == 0 {
ans = min(ans, cnt)
}
for i := 0; i < len(coins); i ++ {
find(coins, amount - coins[i], cnt + 1)
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
方法二:记忆化搜索
将amount为[0,amount]的所有值全部保存起来
import "fmt"
var mem []int
func coinChange(coins []int, amount int) int {
mem = make([]int, amount + 1)
return find(coins, amount)
}
func find(coins []int, amount int) int {
if amount < 0 {
return -1
}
if amount == 0 {
return 0
}
if mem[amount] != 0 {
return mem[amount]
}
ans := math.MaxInt32
for i := 0; i < len(coins); i ++ {
res := find(coins, amount - coins[i])
if res >= 0 {
ans = min(ans, res + 1)
}
}
if ans == math.MaxInt32 {
mem[amount] = -1
} else {
mem[amount] = ans
}
return mem[amount]
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
方法三:动态规划
假设coins[2,3,5],amount=11,考虑最后一次找的硬币为2 or 3 or 5,dp[i]为找钱i时最小的硬币数,则:
ans = min(dp[amount-2], dp[amount-3], dp[amount-5]) + 1(最后一个硬币)。以此类推。最后得到dp[0],dp[1]。
这样就建立了dp[amount]和dp[amount - i]的递推关系。
对与i在[0,amount]的所有取值之间,计算所有dp[i]的值,即找零为i时,最小的硬币数。
func coinChange(coins []int, amount int) int {
dp := make([]int, amount + 1)
for i := 1; i < len(dp); i ++ {
dp[i] = math.MaxInt32
}
dp[0] = 0
for i := 0; i <= amount; i ++ {
for j := 0 ; j < len(coins); j ++ {
if i >= coins[j] {
dp[i] = min(dp[i], dp[i - coins[j]] + 1)
}
}
}
if dp[amount] == math.MaxInt32 {
return -1
}
return dp[amount]
}
func min(a, b int) int {
if a < b {
return a
}
return b
}