At every recursive call I choose 1 more of current denomination or no more of current denomination. I sort the denominations in descending order and use a cache of seen remaining amount. Since I try the higher denomination combinations first, the cache should theoretically have the optimal minimal values for the target remaining amount.
func coinChange(coins []int, amount int) int {
sort.Slice(coins, func(i, j int) bool {
return coins[i] > coins[j]
})
cache := map[int]int{}
var coinChangeDp func(i, target int) int
coinChangeDp = func(i, target int) int {
if target == 0 {
return 0
}
if i >= len(coins) {
return -1
}
cur := coins[i]
if cur == target {
cache[target] = 1
return 1
}
cached, ok := cache[target]
if ok {
return cached
}
if cur < target {
amt := coinChangeDp(i, target-cur)
if amt != -1 {
amt = 1 + amt
}
otherWay := coinChangeDp(i+1, target)
if otherWay == -1 && amt == -1 {
return -1
} else if amt == -1 {
cache[target] = otherWay
return otherWay
} else if otherWay == -1 {
cache[target] = amt
return amt
} else if amt < otherWay {
cache[target] = amt
return amt
} else {
cache[target] = otherWay
return otherWay
}
}
return coinChangeDp(i+1, target)
}
return coinChangeDp(0, amount)
}
It fails on this test case coins= [357,239,73,52] amount = 9832
You can try running the code here: https://leetcode.com/problems/coin-change