416-分割等和子集(01背包)

416-分割等和子集(01背包)

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

注意:

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

示例 1:

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

输出: true

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

示例 2:

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

输出: false

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

基本思路

    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        if(sum % 2 == 1) {
            return false;
        } else {
            // 01背包
            int target = sum / 2;
            int[][] f = new int[nums.length][target + 1];
            for (int v = 0; v <= target; v++) {
                f[0][v] = 0;
            }
            for (int i = 1; i < nums.length; i++) {
                for (int v = nums[i]; v <= target; v++) {
                    f[i][v] = Math.max(f[i - 1][v - nums[i]] + nums[i], f[i - 1][v]);
                    if(f[i][v] == target) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

优化空间复杂度

    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        if(sum % 2 == 1) {
            return false;
        } else {
            // 01背包
            int target = sum / 2;
            int[] f = new int[target + 1];
            target = 10;
            for (int num : nums) {
                for (int v = target; v >= num; v--) {
                    f[v] = Math.max(f[v - num] + num, f[v]);
                    if(f[v] == target) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

其中第二重循环下限可以改进:

    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        if(sum % 2 == 1) {
            return false;
        } else {
            // 01背包
            int target = sum / 2;
            int[] f = new int[target + 1];
            int s = 0;
            target = 10;
            for (int num : nums) {
                for (int v = target; v >= Math.max(s - target, num); v--) {
                    f[v] = Math.max(f[v - num] + num, f[v]);
                    if(f[v] == target) {
                        return true;
                    }
                }
                s += num;
            }
            return false;
        }
    }

或者使用boolean数组:表示能否找到和为i的数组元素集合

            boolean[] f = new boolean[target + 1];
            f[0] = true;
            for (int num : nums) {
                for (int v = target; v >= num; v--) {
                    f[v] = f[v - num] || f[v];
                    if (f[target]) {
                        return true;
                    }
                }
            }
            return f[target];
        boolean[] dp = new boolean[target + 1];
        dp[0] = true;
        for (int num : nums) {
            for (int i = target; i >= num; i--) {
                // 下面的判断语句等价于上面的f[v] = f[v - num] || f[v];
                if (dp[i - num] == true)
                    dp[i] = true;
            }
        }
        return dp[target];

原文地址:https://www.cnblogs.com/angelica-duhurica/p/12242535.html

时间: 2024-10-18 12:25:19

416-分割等和子集(01背包)的相关文章

416分割等和子集

题目:给定一个只包含正整数的非空数组.是否可以将这个数组分割成两个子集,使得两个子集的元素和相等.注意: 每个数组中的元素不会超过 100,数组的大小不会超过 200来源:https://leetcode-cn.com/problems/partition-equal-subset-sum/ 法一:动态规划 思路:首先写状态转移方程的时候,如果采用类似312戳气球的方法,即由内到外,由小到大,是难以实现的,原因有二,一是假如题目中的数组元素有6个,则dp[1]即长度为1的子集有6个,dp[2]长

动态规划01背包记录

01背包是动态规划的一种类型其主要的形式是: 1.所有类型物品每种类型只有一个 2.一次只能取一个且物品不能分割 3.只有取或者不取(所以叫01背包,就是只有这两种情况) 4.在背包容量不满的前提下尽可能多的装入最大价值的物品 设背包的容量为V,第i个物品的重量为weigh[i]对应的价值为price[i];  设容量为j(j的最大值为背包的容量)的背包所能装的最大价值为dp[j] n为所有的物品个数,我们先从第1个数据开始,则此物品重量为weigh[1],则我们将所有大于weigh[1]的背包

01背包//简直要被这道题玩死(掀桌)

先上链接: 表格什么的最清楚了:http://blog.csdn.net/mu399/article/details/7722810 dd大大的背包九讲: —————————————————— 01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] } f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值. Pi表示第i件物品的价值. 决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中

494-目标和(转化为01背包)

494-目标和(转化为01背包) 给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S.现在你有两个符号 + 和 -.对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面. 返回可以使最终数组和为目标数 S 的所有添加符号的方法数. 示例 1: 输入: nums: [1, 1, 1, 1, 1], S: 3 输出: 5 解释: -1+1+1+1+1 = 3 +1-1+1+1+1 = 3 +1+1-1+1+1 = 3 +1+1+1-1+1 = 3 +1+1+

动态规划--01背包模型

01背包剖析 问题引入 题目来源:ACwing:01背包问题 有 N 件物品和一个容量是 V 的背包.每件物品只能使用一次.第 i 件物品的体积是 vi,价值是 wi.求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大.输出最大价值. 输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积. 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值. 输出格式 输出一个整数,表示最大价值. 数据范围 0<N,V≤1000

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

17-又见01背包

/*                                        又见01背包时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述        有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W     的物品,求所有挑选方案中物品价值总和的最大值.    1 <= n <=100    1 <= wi <= 10^7    1 <= vi <= 100    1 <= W <= 10^

HDU - 2602 Bone Collector(01背包讲解)

题意:01背包:有N件物品和一个容量为V的背包.每种物品均只有一件.第i件物品的费用是volume[i],价值是value[i],求解将哪些物品装入背包可使价值总和最大. 分析: 1.构造二维数组:dp[i][j]---前i件物品放入一个容量为j的背包可以获得的最大价值. dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volume[i]] + value[i]);---(a) (1)dp[i - 1][j]---不放第i件物品,因此前i件物品放入一个容量为

01背包

这里就只放自己刷的题目了,毕竟是弱弱哒 HDU2546:饭卡 1 #include <algorithm> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int n,m; 9 while (~scanf("%d", &n), n) 10 { 11 int f[2013] = {0}, menu[2013] = {0}; 12 for (int i = 1; i <