[代码随想录]Day37-动态规划part05

发布时间 2023-09-06 10:12:42作者: WtcSky

题目:1049. 最后一块石头的重量 II

思路:

和昨天的类似,越靠近和的一半剩下的就越少。
相对于 01背包,本题中,石头的重量是 stones[i],石头的价值也是 stones[i] ,可以 “最多可以装的价值为 dp[j]” == “最多可以背的重量为dp[j]”

代码:

func lastStoneWeightII(stones []int) int {
    sum := 0
    for _, x := range stones {
        sum += x
    }
    half := sum / 2
    dp := make([]int, half+1)
    for i:=0; i <len(stones); i++ {
        for j := half; j >= stones[i]; j-- {
            dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
        }
    }
    return sum - 2 * dp[half]
}
func max(a,b int) int {
    if a > b {
        return a
    }
    return b
}

参考:

代码随想录

题目:494. 目标和

思路:

本题要如何使表达式结果为target,既然为target,那么就一定有 left组合 - right组合 = target。left + right = sum,而sum是固定的。right = sum - left
公式来了, left - (sum - left) = target 推导出 left = (target + sum)/2
target是固定的,sum是固定的,left就可以求出来。
此时问题就是在集合nums中找出和为left的组合。

有哪些来源可以推出dp[j]呢?
只要搞到nums[i],凑成dp[j]就有dp[j - nums[i]] 种方法。
例如:dp[j],j 为5,

  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 容量为5的背包。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 容量为5的背包。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 容量为5的背包
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 容量为5的背包
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 容量为5的背包

那么凑整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。

代码:

func findTargetSumWays(nums []int, target int) int {
    sum := 0
    for _ , x := range nums {
        sum += x
    }
    if abs(target) > sum {
        return 0
    }
    if (sum + target) % 2 != 0 {
        return 0
    }
    mx := (sum + target) / 2 // 只要有这个数就可以
    dp := make([]int, mx + 1)
    dp[0] = 1
    for i:=0;i<len(nums);i++ {
        for j:=mx;j>=nums[i];j--{
            dp[j] += dp[j-nums[i]]
        }
    }
    return dp[mx]
}
func abs(a int) int {
    if a < 0 {
        return -a
    }
    return a
}

参考:

代码随想录

题目:474. 一和零

思路:

dp[i][j] 可以由前一个strs里的字符串推导出来,strs里的字符串有zeroNum个0,oneNum个1。
dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
然后我们在遍历的过程中,取dp[i][j]的最大值。
所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
此时大家可以回想一下01背包的递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
对比一下就会发现,字符串的zeroNum和oneNum相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])。
这就是一个典型的01背包! 只不过物品的重量有了两个维度而已。

代码:

func findMaxForm(strs []string, m int, n int) int {
    dp := make([][]int, m+1)
    for i, _ := range dp {
        dp[i] = make([]int, n+1)
    }
    for i:=0;i<len(strs);i++ {
        zeroNum, oneNum := Calc(strs[i])
        for j:=m;j>=zeroNum;j-- {
            for k:=n;k>=oneNum;k-- {
                dp[j][k] = max(dp[j][k], dp[j-zeroNum][k-oneNum]+1)
            }
        }
    }
    return dp[m][n]
}
func max(a,b int)int {
    if a > b {
        return a
    }
    return  b
}
func Calc(s string)(zero, one int) {
    for _, v := range s {
        if v == '0' {
            zero++
        }else {
            one++
        }
    }
    return
}

参考:

代码随想录