LeetCode416 -- 总结0-1背包问题 -- 动态规划

0-1 背包

有一个容量为 N 的背包,要用这个背包装下物品的价值最大,这些物品有两个属性:体积 w 和价值 v。

定义一个二维数组 dp 存储最大价值,其中 dp[i][j] 表示前 i 件物品体积不超过 j 的情况下能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论:

  • 第 i 件物品没添加到背包,总体积不超过 j 的前 i 件物品的最大价值就是总体积不超过 j 的前 i-1 件物品的最大价值,dp[i][j] = dp[i-1][j]。
  • 第 i 件物品添加到背包中,dp[i][j] = dp[i-1][j-w] + v。

第 i 件物品可添加也可以不添加,取决于哪种情况下最大价值更大。因此,0-1 背包的状态转移方程为:

就是当前看到第i个物品了,允许的体积是j的时候  的最大价值。

416. 分割等和子集

给定一个只包含正整数非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

注意:

  1. 每个数组中的元素不会超过 100
  2. 数组的大小不会超过 200

示例 1:

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2:

输入: [1, 2, 3, 5]

输出: false

解释: 数组不能分割成两个元素和相等的子集.

解题思路

看到这道题是想用回溯做,但是时间超时。

其实这是一道01背包的题。

class Solution {
     public boolean canPartition(int[] nums) {
        /*
        动态规划 相当于用空间换时间
        dp[i][j] 表示看到i的时候总和能不能等于j ,
           如果i之前就有==j了,那么dp[i][j] == true;
           如果i之前有等于j - nums[i],dp[i][j]也是true
           否则dp[i][j]就是false了

         */
        int len = nums.length;
        int sum = 0;
        for (int i = 0;i < len;i++){
            sum += nums[i];
        }
        if (sum % 2 != 0){
            return false;
        }
        int target = sum/2;
        boolean[][] dp = new boolean[len][target + 1];
        for (int j = 0;j < target + 1;j++){  //先把第一行写好
            if (j == nums[0]){
                dp[0][j] = true;
            }
        }
        dp[0][0] = true; //00也初始化成true 啥也不放
        for (int i = 1; i < len; i++) {
            for (int j = 0; j < target + 1; j++) {
                if (dp[i - 1][j] == true){  // 不用看当前的数就可以到j
                    dp[i][j] = true;
                }

                else if (j - nums[i] >= 0 && dp[i - 1][j - nums[i]] == true){ //i之前的数 加上 nums[i] 能到j也是可以
                    dp[i][j] = true;
                }

                if (dp[i][target] == true){ //看到当前的数时能得到target,直接返回true就 好了
                    return true;
                }
            }
        }
        return false;
    }
}

 

你可能感兴趣的:(leetcode,01背包)