LeetCode Day42 416

69 阅读2分钟

01背包问题 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

  1. 确定dp数组以及下标的含义:背包问题有一种写法, 是使用二维数组,即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少
  2. 递推公式:考虑放入物品和不放物品两种情况。
416. 分割等和子集

这题要找是否能把子集分割成俩个相等的集合,所以把集合里的数求和sum以后除以2,能除开的话就算是可以分割成两个相同元素和子集了。

  1. 确定dp数组以及下标的含义:把这个问题当成01背包问题去思考,dp[i]表示当前第i个物品能装进背包的值,如果背包容量为target, dp[target]就是装满背包之后的重量。当dp[target]==target成立时,说明可以分割出一个等和子集。
  2. 确定递推公式:01背包的公式是dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);本题相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  3. dp初始化:dp[0]=0
  4. 确定遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历
class Solution {
    public boolean canPartition(int[] nums) {
        int n = nums.length;
        if(nums == null || n == 0) return false;
        int sum = 0;
        for(int i : nums){
            sum += i;
        }

        int target  = sum / 2;
        if(sum % 2 != 0){
            return false;
        }
        
        int[] dp = new int[target + 1];

        for(int i = 0; i < n; i ++){
            for(int j = target; j >=nums[i]; j --){
                dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            }

            if(dp[target] == target) return true;
        }

        return dp[target] == target;

    }
}