力扣-动态规划-416. 分割等和子集

27 篇文章 0 订阅
26 篇文章 0 订阅

力扣-动态规划-416. 分割等和子集

416. 分割等和子集

题目描述

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

示例 1:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:
输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100

解题思路:动态规划

 前面好几天没有写博客了。每天有在坚持学习和刷题,最近毕业论文要开题了,每天时间很紧,但不写博客又总觉得自己一天啥都没学。所以我决定不管再忙还是要坚持写博客,对每天的学习和刷题做一个总结。
 今天开始刷动态规划中关于01背包的题目,对01背包的基本理论知识做了一个系统了解,初步学会了用二维dp数组和一维dp数组来解决直接的01背包问题。然后尝试了第一道01背包的题目,说实话,如果不是事先知道这道题可以用01背包来解决,我恐怕很难想到。
 这道题我首先想到的是用回溯算法来暴力求解,中间加一些剪枝操作。代码调试好之后已提交,哦豁,超时了。于是看了答案的01背包思路,用01背包的思想来解决这道题。
 在正式开始写代码之前,需要先想清楚这道题用什么方法,会用到哪些数据结构,我觉得这个很重要。提前把思路理清楚,并考虑好数据结构,剩下的就是具体代码的实现。
 这道题有两个地方不太好想:1.分割的两个子集的和都是大的集合的一半,这是我们需要找到的第一个条件。集合的和的一半将作为背包的容量,每个元素的值是物品的重量也是物品的价值。
2.既然每个元素的重量和价值一样,由于背包中元素的重量和一定是小于等于背包容量的,所以背包中物品的价值最大也就不会超过背包的容量。我们就将问题转化为了判断背包中物品在给定容量条件下能够达到的最大价值是否等于背包的容量,如果最大价值跟背包容量相等,说明子集的和刚好就是大集合的一半。
 理解了上面两点,这道题就知道该怎么用01背包来套了。
 我自己写的代码如下,代码已经加了注释,各位小伙伴如果有什么问题可以在评论里提出来,欢迎大家交流。

//套用01背包 将子集的和作为背包的容量 元素的数值同时作为重量和价值
    //核心点在于 理解到背包中物品的最大价值与背包的容量是一致的,并且物品的最大价值不会超过背包的容量
    //我们想要的结果是背包中物品的价值达到背包的容量,背包物品最大价值不会超过背包的容量,
    //因此本题就转化为了背包问题
    //用一维滚动数组来求解
    //1.确定dp[i]的含义 dp[i]代表最大和可以凑成i的子集的总和
    //2.递归公式 dp[j] = max(dp[j], dp[j - weight[i]] + value[j])
    //3.dp初始化 01背包的初始化方式
    //4.遍历方式 外层遍历物品,内层遍历容量
    //5.举例推导
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int ele : nums) {
            sum += ele;
        }
        if (sum % 2 == 1) {//和为奇数不能平分为两部分
            return false;
        }
        int length = sum/2 + 1;
        int[] dp = new int[length];
        //初始化dp数组
        for (int i = nums[0]; i < length; i++) {
            dp[i] = nums[0];
        }
        for (int i = 1; i < nums.length; i++) {
            for (int j = length - 1; j >= nums[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            }
            if (dp[length - 1] == length - 1) {
                return true;
            }
        }
        return false;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值