1.目标和
这里设置背包的最大长度为2100即可,因为题目中有说数组之和小于1000.但考虑到我们需要实行j+nums[i]所以保守起见我们设置的数应该稍大于2000即可,这里我们设置为2100。
1.1 我的解法(粗糙了)
func findTargetSumWays(nums []int, target int) int {//dp[i][j],这里的i代表nums中的前i个数,j代表targetn := len(nums)dp := make([][]int, n)maxNum := 2100for i := 0; i < n; i++ {dp[i] = make([]int, maxNum+1)}if nums[0] == 0 {dp[0][nums[0]] = 2} else {dp[0][nums[0]] = 1}for i := 1; i < n; i++ {for j := 0; j < maxNum-1000; j++ {target1 := abs(j - nums[i])target2 := abs(j + nums[i])if target1 != target2 || j == 0 || nums[i] == 0 {dp[i][j] = dp[i-1][target1] + dp[i-1][target2]} else {dp[i][j] = dp[i-1][target1]}}}return dp[n-1][abs(target)]
}func abs(a int) int {if a > 0 {return a}return -a
}
1.2 它解
假设加法的总和为x,那么减法对应的总和就是sum - x。
所以我们要求的是 x - (sum - x) = target
x = (target + sum) / 2
此时问题就转化为,装满容量为x的背包,有几种方法。
这里的x,就是bagSize,也就是我们后面要求的背包容量。
大家看到(target + sum) / 2 应该担心计算的过程中向下取整有没有影响。
这么担心就对了,例如sum 是5,S是2的话其实就是无解的。
func findTargetSumWays(nums []int, target int) int {sum := 0for _, v := range nums {sum += v}//target的绝对值已经大于sumif abs(target) > sum {return 0}//要么全为奇数,要么全为偶数if (sum+target)%2 == 1 {return 0}// 计算背包大小bag := (sum + target) / 2// 定义dp数组dp := make([]int, bag+1)// 初始化dp[0] = 1// 遍历顺序for i := 0; i < len(nums); i++ {for j := bag; j >= nums[i]; j-- {//推导公式dp[j] += dp[j-nums[i]]//fmt.Println(dp)}}return dp[bag]
}func abs(x int) int {return int(math.Abs(float64(x)))
}
2.一和零
思路:这里将i表示0的个数,j表示1的个数
当i大于等于字符串中0的个数且j大于等于字符串中1的个数时,可以得到递推公式为
dp[i][j] = max(dp[i][j], dp[i-itemList[k].num0][j-itemList[k].num1]+1)
func findMaxForm(strs []string, m int, n int) int {dp := make([][]int, m+1)for i := 0; i <= m; i++ {dp[i] = make([]int, n+1)}itemList := make([]*Item, 0)for i := 0; i < len(strs); i++ {num0, num1 := getCountOf01(strs[i])itemList = append(itemList, &Item{num0: num0, num1: num1})}//i表示0的个数,j表示1的个数for k := 0; k < len(strs); k++ {for i := m; i >= itemList[k].num0; i-- {for j := n; j >= itemList[k].num1; j-- {dp[i][j] = max(dp[i][j], dp[i-itemList[k].num0][j-itemList[k].num1]+1)}}//for i := 0; i <= m; i++ {// fmt.Println(dp[i])//}//fmt.Println("==========")}return dp[m][n]
}func max(a, b int) int {if a > b {return a}return b
}type Item struct {num0, num1 int
}func getCountOf01(str string) (num0, num1 int) {for i := 0; i < len(str); i++ {if str[i:i+1] == "0" {num0++} else if str[i:i+1] == "1" {num1++}}return
}
3.完全背包理论基础
https://kamacoder.com/problempage.php?pid=1052
和零一背包的区别在于,这里面的材料可以重复拾取。
// test_CompletePack1 先遍历物品, 在遍历背包
func test_CompletePack1(weight, value []int, bagWeight int) int {// 定义dp数组 和初始化dp := make([]int, bagWeight+1)// 遍历顺序for i := 0; i < len(weight); i++ {// 正序会多次添加 value[i]for j := weight[i]; j <= bagWeight; j++ {// 推导公式dp[j] = max(dp[j], dp[j-weight[i]]+value[i])// debug//fmt.Println(dp)}}return dp[bagWeight]
}// test_CompletePack2 先遍历背包, 在遍历物品
func test_CompletePack2(weight, value []int, bagWeight int) int {// 定义dp数组 和初始化dp := make([]int, bagWeight+1)// 遍历顺序// j从0 开始for j := 0; j <= bagWeight; j++ {for i := 0; i < len(weight); i++ {if j >= weight[i] {// 推导公式dp[j] = max(dp[j], dp[j-weight[i]]+value[i])}// debug//fmt.Println(dp)}}return dp[bagWeight]
}func max(a, b int) int {if a > b {return a}return b
}
4.零钱兑换II
func change(amount int, coins []int) int {// 定义dp数组dp := make([]int, amount+1)// 初始化,0大小的背包, 当然是不装任何东西了, 就是1种方法dp[0] = 1// 遍历顺序// 遍历物品for i := 0; i < len(coins); i++ {// 遍历背包for j := coins[i]; j <= amount; j++ {// 推导公式dp[j] += dp[j-coins[i]]}}return dp[amount]
}