diff --git a/go/41_dynamic_programming/backtracking/leastcoins.go b/go/41_dynamic_programming/backtracking/leastcoins.go new file mode 100644 index 0000000..6757820 --- /dev/null +++ b/go/41_dynamic_programming/backtracking/leastcoins.go @@ -0,0 +1,102 @@ +package dp + +import ( + "fmt" +) + +const intMax = int(^uint(0) >> 1) + +var Cnt int + +// LeastCoins find least number of coins of which the total values are equals a given one +func LeastCoins(targetTotal int, coinOptions []int) int { + minNum := intMax + + memo := make([][]int, targetTotal+1) + for i := range memo { + memo[i] = make([]int, len(coinOptions)) + } + fmt.Println("start") + leastCoins(&minNum, 0, targetTotal, len(coinOptions)-1, coinOptions, memo) + fmt.Println("end") + + return minNum + +} + +func leastCoins(minNum *int, cNum, totalValue, opIndex int, coinOptions []int, memo [][]int) { + Cnt++ + if 0 == totalValue { + if cNum < *minNum { + *minNum = cNum + } + + return + } + + if opIndex < 0 { + return + } + + num4Option := 0 + remaining := totalValue - coinOptions[opIndex]*num4Option + for remaining >= 0 { + + if opIndex != 0 { + if shouldSkip(memo, remaining, opIndex-1, cNum+num4Option) { + goto Next + } + } + leastCoins(minNum, cNum+num4Option, remaining, opIndex-1, coinOptions, memo) + + Next: + num4Option++ + remaining = totalValue - coinOptions[opIndex]*num4Option + + } + +} + +func shouldSkip(memo [][]int, totalValue, nextOpIdex, cNum int) bool { + if memo[totalValue][nextOpIdex] > 0 && memo[totalValue][nextOpIdex] <= cNum { + fmt.Printf("skip,%d, %d as %d <= %d \n", totalValue, nextOpIdex, memo[totalValue][nextOpIdex], cNum) + return true + } + if memo[totalValue][nextOpIdex] == 0 || memo[totalValue][nextOpIdex] > cNum { + memo[totalValue][nextOpIdex] = cNum + } + return false +} + +func LeastCoins2(targetTotal int, coinOptions []int) int { + + minNum := intMax + memo := make([][]bool, targetTotal) + for i := range memo { + memo[i] = make([]bool, targetTotal/coinOptions[0]) + } + + fmt.Println("start") + leastCoins2(&minNum, targetTotal, coinOptions, 0, 0, memo) + fmt.Println("end") + + return minNum + +} + +func leastCoins2(minNum *int, targetTotal int, coinOptions []int, cNum, cValue int, memo [][]bool) { + Cnt++ + if cValue == targetTotal { + if *minNum > cNum { + *minNum = cNum + } + return + } + + for _, coin := range coinOptions { + if coin+cValue <= targetTotal && !memo[cValue+coin-1][cNum] { + memo[cValue+coin-1][cNum] = true + leastCoins2(minNum, targetTotal, coinOptions, cNum+1, cValue+coin, memo) + } + } +} diff --git a/go/41_dynamic_programming/backtracking/leastcoins_test.go b/go/41_dynamic_programming/backtracking/leastcoins_test.go new file mode 100644 index 0000000..ff75f09 --- /dev/null +++ b/go/41_dynamic_programming/backtracking/leastcoins_test.go @@ -0,0 +1,56 @@ +package dp + +import "testing" + +func TestFindLeastCoins(t *testing.T) { + + coinOptions := []int{1, 3, 5, 10, 50} + + Cnt = 0 + result := LeastCoins(9, coinOptions) + + t.Log("test 1 =====================") + if result != 3 { + t.Logf("least coins %d", result) + t.Error("failed") + } + t.Logf("cnt===%d", Cnt) + + Cnt = 0 + t.Log("test 2 =====================") + result = LeastCoins(36, coinOptions) + + if result != 5 { + t.Logf("least coins %d", result) + t.Error("failed") + } + t.Logf("cnt===%d", Cnt) + +} + +func TestFindLeastCoins2(t *testing.T) { + + coinOptions := []int{1, 3, 5, 10, 50} + + Cnt = 0 + result := LeastCoins2(9, coinOptions) + + t.Log("test 1 =====================") + if result != 3 { + t.Logf("least coins %d", result) + t.Error("failed") + } + + t.Logf("cnt===%d", Cnt) + + Cnt = 0 + t.Log("test 2 =====================") + result = LeastCoins2(36, coinOptions) + + if result != 5 { + t.Logf("least coins %d", result) + t.Error("failed") + } + t.Logf("cnt===%d", Cnt) + +}