322 零錢找還
func coinChange(coins []int, amount int) int {
// 裝滿,並且硬幣無限,可以類比完全揹包問題
// dp[i][j] 表示前i個物品裝滿容量為j的揹包所需要的最少物品數量
// 遞推公式 dp[i][j] = min(dp[i-1][j], dp[i][j-w(i)]+1) // 不裝物品i的物品數量,裝物品i的物品數量
// 初始化 dp[0][0] = 0, 其他數值為math.minint
// 遍歷順序,本題沒有要求全排列或者全組合,所以用了二維,二維順序是無所謂的,但是習慣還是先物品後背包
// print
var dp = make([][]int, len(coins) + 1)
for idx, _ := range dp {
dp[idx] = make([]int, amount + 1)
for j := range dp[idx] {
dp[idx][j] = amount + 1 // 用來表示一個無法湊成的最大金額,方便在min操作時取到正確的最小值
}
}
dp[0][0] = 0
for i:=0; i<len(coins); i++{
for j:=0; j<=amount; j++{
if j-coins[i] >= 0 { // 要滿足剩餘揹包容量大於等於0
dp[i+1][j] = min(dp[i][j], dp[i+1][j-coins[i]]+1)
}else {
dp[i+1][j] = dp[i][j]
}
}
}
//fmt.Println(dp)
if dp[len(coins)][amount] > amount {
return -1
}
return dp[len(coins)][amount]
}
func min(x,y int )int {
if x < y{
return x
}
return y
}
// 本題思路好找,難點在於取最小值的時候是否能夠想到將dp陣列初始化為一個比較大的數,而不是0
func coinChange(coins []int, amount int) int {
// 裝滿,並且硬幣無限,可以類比完全揹包問題
// dp[j] 表示裝滿容量為j的揹包所需要的最少物品數量
// 遞推公式 dp[j] = min(dp[j], dp[j-w(i)]+1) // 不裝物品i的物品數量,裝物品i的物品數量
// 初始化 dp[0] = 0, 其他數值為amount + 1, 這裡表示如果全是1來組成amount,需要amount個1,這已經時需要的最大數量,那我設定amount+1,就是要比最大值還要大
// 遍歷順序,本題沒有要求全排列或者全組合,完全揹包一位陣列按照習慣先正序物品,後正序揹包
// print
var dp = make([]int, amount + 1)
for i, _ := range dp {
dp[i] = amount + 1
}
dp[0] = 0
for i:=0; i<len(coins); i++{
for j:=0; j<=amount; j++{
if j-coins[i] >= 0 { // 要滿足剩餘揹包容量大於等於0
dp[j] = min(dp[j], dp[j-coins[i]]+1)
}
}
}
//fmt.Println(dp)
if dp[amount] > amount {
return -1
}
return dp[amount]
}
func min(x,y int )int {
if x < y{
return x
}
return y
}
279 完全平方數
func numSquares(n int) int {
// 完全揹包
// dp[j] 表示裝滿容量j的揹包需要最少完全平方數
// 遞推 dp[j] = min(dp[j], dp[j-i^2] + 1)
// dp[0] = 0 其他初始化成為n+1
// 先正序物品,後正序揹包 揹包0->n 物品0->n開方+1
// print
var dp = make([]int, n+1)
s := int(math.Sqrt(float64(n))) + 1
for idx, _ := range dp {
dp[idx] = n+1
}
dp[0] = 0
for i:=1; i<=s; i++ {
for j:=i*i; j<=n; j++{
dp[j] = min(dp[j], dp[j-i*i]+1)
}
}
fmt.Println(dp)
return dp[n]
}
139 單詞拆分
func wordBreak(s string, wordDict []string) bool {
// 本題可以聯想到完全揹包問題,但是難點在於,1 dp陣列含義 2 遞推公式 3 遍歷順序
// dp[j] 表示前j個字母能夠唄字典中的單詞拼出
// 遞推公式,對於每一個單詞 dp[j] = dp[j-len()] && true 表示本單詞+目標-本單詞長度剩餘的單詞能否被拼出
// 遍歷順序,字典可能被多次使用,並且順序可以顛倒,所以時全排列,先正序揹包,後正序物品
// print
m := minlength(wordDict)
if len(s) < m {
return false
}
var dp = make([]bool, len(s) + 1)
dp[0] = true
for j:=m-1; j<len(s); j++ {
for i:=0; i<len(wordDict); i++{
diff := j-len(wordDict[i])+1
if diff >= 0 && s[diff: j+1] == wordDict[i]{
dp[j+1] = dp[diff]
}
if dp[j+1] == true {
break
}
}
}
//fmt.Println(dp)
return dp[len(s)]
}
func minlength(dict []string) int {
var m int = math.MaxInt
for _, v := range dict{
if len(v) < m {
m = len(v)
}
}
return m
}