头脑风暴:分割等和子集

网友投稿 239 2022-11-29

头脑风暴:分割等和子集

题目

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

注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200

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

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

提示:

1 <= nums.length <= 200 1 <= nums[i] <= 100

解题思路

根据题意,本题可以使用 01 背包问题来求解。这道题目是要找是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。

根据我之前写的求解 01 背包问题的解法,我们只要套路这种解题方式就可以将此题求解。

第一步确定 dp 数组,01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值可以最大为dp[j]。套到本题,dp[j]表示背包总容量是j,最大可以凑成j的子集总和为dp[j]。

第二步确定递推公示:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]),nums[i] 表示物品的价值。

第三步dp数组初始化,根据前一篇文章的说明,只要是包含正整数的非空数组,就将 dp 数组初始化为 0 即可。

第四步确定遍历顺序,本题我们使用一维数组,所以使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历。代码如下:

for(int i = 0; i < nums.size(); i++) { for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历

代码实现

class Solution { public boolean canPartition(int[] nums) { if(nums == null || nums.length == 0) return false; int n = nums.length; int sum = 0; for(int num : nums){ sum += num; } //总和为奇数,不能平分 if(sum % 2 != 0) return false; int target = sum / 2; int[] dp = new int[target + 1]; for(int i = 0; i < n; i++){ for(int j = target; j >= nums[i]; j--){ //物品 i 的重量是 nums[i],其价值也是 nums[i] dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]); } } return

最后

时间复杂度:O(n^2)空间复杂度:O(n)

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:手撸二叉树之从根到叶的二进制数之和
下一篇:java 方法重写与权限修饰符以及多态和抽象类详解概念和用法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~