代码随想录day36|背包问题416分割等和子集|01笔记

113 阅读2分钟
  • 背包问题

  • 二维

  • 代码随想录 (programmercarl.com)
  • 一维

  • 01背包-滚动数组
  • 416分割等和子集

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 可以分割成等和子集的前提是自己元素和为偶数。所以首先需要判定子元素和。暴力方法可以通过回溯寻找子子集,但超时。尝试使用线性规划,但一时想不出dp数组的意义。
  • 讲解观后感

  • 只有确定了如下四点,才能把01背包问题套到本题上来。
  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。
  • 01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。
  • 本题中每一个元素的数值既是重量,也是价值。
  • 套到本题,dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]
  • 想清楚了背包容量就是价值的道理,本题就容易推进了。
  • 当容量为target时,由于我们背包问题的方法是求解最大价值,所以如果可以填满,那么一定会填满。
  • 解题代码

  •     // 时间复杂度O(n^2) 空间复杂度O(n)
        func canPartition(nums []int) bool {
            sum := 0
            for _, num := range nums {
                sum += num
            }
            // 如果 nums 的总和为奇数则不可能平分成两个子集
            if sum % 2 == 1 {
                return false
            }
            
            target := sum / 2
            dp := make([]int, target + 1)
            for _, num := range nums {
                for j := target; j >= num; j-- {
                    if dp[j] < dp[j - num] + num { // dp[j] = max(dp[j], dp[j-num] + num)
                        dp[j] = dp[j - num] + num
                    }
                }
            }
            /*
            for i:=0;i<len(nums);i++ {
                for j:=target;j>=nums[i];j-- {
                    if dp[j] < dp[j-nums[i]] + nums[i] {
                        dp[j] = dp[j-nums[i]] + nums[i]
                    }
                }
            }
            */
            return dp[target] == target
        }
    
  • 二维
  •     // 时间复杂度O(n^2) 空间复杂度O(n)
        func canPartition(nums []int) bool {
            sum := 0
            for _, num := range nums {
                sum += num
            }
            // 如果 nums 的总和为奇数则不可能平分成两个子集
            if sum % 2 == 1 {
                return false
            }
            ans := false
            target := sum / 2
            dp := make([][]int, len(nums))
            for l:=0;l<len(nums);l++ {
                dp[l] = make([]int, target+1)
            }
            for i:=0;i<len(nums);i++ {
                dp[i][0] = 0
            }
            for i:=0;i<target+1;i++ {
                dp[0][i] = 0
            }
            for i:=1;i<len(nums);i++ {
                for j:=1;j<=target;j++ {
                    if nums[i] > j {
                        dp[i][j] = dp[i-1][j]
                    } else {
                        dp[i][j] = mx(dp[i-1][j], dp[i-1][j-nums[i]] + nums[i])
                    }
                    if j == target {
                        if dp[i][j] == target {
                            ans = true
                        }
                    }
                }
            }
            return ans
        }
        
        
        
        func mx(x int, y int) int {
            if x > y {
                return x
            } else {
                return y
            }
        }