分割等和子集——动态规划

105 阅读2分钟

image.png

代码1:

  1. 长度小于2,特判false,和为奇数,特判false,最大值大于和的一半,特判false
  2. 接下来,0-1背包问题,动态规划,建立dp[i][j]bool二维切片,i 表示nums[:i+1],j 表示和,也就是0-1背包里的重量,dp[i][j]bool就表示在nums[:i+1]中是否可以找出和为 j 的情况
  3. 初始化dp切片,第一列,也就是 j 等于 0 的情况,那自然是true,因为你只需要一个数字不选,那么和就是0,
  4. 初始化第一排,也就是 i == 0 的情况,i == 0,除了刚好 j == nums[i]这种情况,其余都是false,因为初始化默认就是false,所以我们只需要dp[0][nums[0]] = true就可以了(但其实不初始化这个也可以)
  5. i > 0, j > 0的情况,我们只需要考虑当前的nums[i]这个值我们选不选就可以了,这两种情况只要一个满足true,当前的dp就可以为true,即dp[i][j] = dp[i-1][j] || dp[i-1][j-v],
  6. 但是我们要保证 j-v > 0,也就是当前值一定要小于j,如果大于,我们只能选择,不选这个值这种情况dp[i][j] = dp[i-1][j]
func canPartition(nums []int) bool {
    n := len(nums)
    if n < 2 {
        return false
    }
    a, max := 0, 0
    for _,v := range nums {
        a = a + v
        if max < v {
            max = v
        }
    }
    if a % 2 != 0 {
        return false
    }
    a = a >>1
    if a < max {
        return false
    }
    dp := make([][]bool, n)
    for i := range dp {
        dp[i] = make([]bool,a+1)
    }
    for i := 0; i < n; i++ {
        dp[i][0] = true
    }
    dp[0][nums[0]] = true
    for i := 1; i < n; i++ {
        v := nums[i]
        for j := 0; j <= a; j++ {
            if j >= v {
                dp[i][j] = dp[i-1][j] || dp[i-1][j-v]
            }else {
                dp[i][j] = dp[i-1][j]
            }
        }
    }
    return dp[n-1][a] 
}

代码2:

  1. 但是可以发现在计算 dp 的过程中,每一行的 dp 值都只与上一行的 dp 值有关,因此只需要一个一维数组即可此时的转移方程为:dp[j]=dp[j] ∣dp[j−nums[i]]
  2. 注意第二层循环需要从大到小计算,因为如果我们不使用辅助空间,直接在原dp切片上直接进行操作,那么在计算dp[j]=dp[j−nums[i]]时,dp[j−nums[i]]已经是更新过的状态,不再是上一行的dp值了,
  3. 既然是从大到小计算,j < v 的情况也不需要考虑了,直接继承就可以了,不用更新
func canPartition(nums []int) bool {
    n := len(nums)
    if n < 2 {
        return false
    }
    a, max := 0, 0
    for _,v := range nums {
        a = a + v
        if max < v {
            max = v
        }
    }
    if a % 2 != 0 {
        return false
    }
    a = a >>1
    if a < max {
        return false
    }
    dp := make([]bool, a+1)
    dp[0] = true
    for i := 1; i < n; i++ {
        v := nums[i]
        for j := a; j >= v; j-- {
            dp[j] = dp[j] || dp[j-v]
        }
    }
    return dp[a] 
}