【Leetcode】416. 分割等和子集

博客介绍了LeetCode上的416题——分割等和子集,讨论了如何判断一个包含正整数的数组是否能分割成两个和相等的子集。通过分析得出,数组元素的和需为偶数,数组长度大于1,且最大值不能超过总和的一半。最初尝试使用排序后的回溯法,但未能解决所有情况。最终采用动态规划的0-1背包问题思路,定义dp数组,通过状态转移方程解决。优化后的时间复杂度为O(n target),空间复杂度降低到O(target)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:分割等和子集

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

思路:将数组分割成两个等和的子集。

那么:

1)数组元素的和肯定得是偶数,并且数组长度必须大于1。且数组最大值不能大于数组和的一半

2)问题转换为:数组中是否存在若干个元素,其和为数组所有元素和的一半。即寻找若干元素的和为target。

本来的思路是:将元素排序,然后使用回溯的方法,通过了100多个样例。剩下几个样例错误,经过反复思考和尝试发现回溯的方法并不对。

于是看了题解,恍然大悟。

0-1背包问题:

有n个物体和一个背包,将n个物体中的若干个物体放入背包。每个物体只能放1次,即每个物体都是要么放,要么不放。

对应这道题就是,n个物体中选若干个放入一个大小为target的背包,能否刚好装满。

定义一个数组dp[n][target+1],dp[i][j]表示能否从前[0,i]个数中选取若干个使其和刚好为j。最终dp[n-1][target]即为所求。采用了动态规划的思想。

因为每一个物体都可放可不放,所以就有了分类讨论,即得到状态转移方程。

如果j==nums[i],则只放第i个物体即可,即dp[i][j]=true,

如果j<nums[i],则第 i个物体不能放入大小为j的背包里,只能从前[0,i-1]个物体中去取,即dp[i][j]=dp[i-1][j]。

如果j>nums[i],那么第i个物体可以放入大小为j的背包里,也可以选择不放。即dp[i][j]

题目描述: 给定一个只包含正整数的非空数组,是否可以将这个数组分成两个子集,使得两个子集的元素相等。 示例: 输入:[1, 5, 11, 5] 输出:true 解释:数组可以分割成 [1, 5, 5] [11]。 解题思路: 这是一道经典的 0-1 背包问题,可以使用动态规划或者回溯算法解决。 使用回溯算法,需要定义一个 backtrack 函数,该函数有三个参数: - 数组 nums; - 当前处理到的数组下标 index; - 当前已经选择的元素 leftSum。 回溯过程中,如果 leftSum 等于数组元素的一半,那么就可以直接返回 true。如果 leftSum 大于数组元素的一半,那么就可以直接返回 false。如果 index 到达数组末尾,那么就可以直接返回 false。 否则,就对于当前元素,有选择不选择两种情况。如果选择当前元素,那么 leftSum 就加上当前元素的值,index 就加 1。如果不选择当前元素,那么 leftSum 不变,index 也加 1。最终返回所有可能性的结果中是否有 true。 Java 代码实现: class Solution { public boolean canPartition(int[] nums) { int sum = 0; for (int num : nums) { sum += num; } if (sum % 2 != 0) { return false; } Arrays.sort(nums); return backtrack(nums, nums.length - 1, sum / 2); } private boolean backtrack(int[] nums, int index, int leftSum) { if (leftSum == 0) { return true; } if (leftSum < 0 || index < 0 || leftSum < nums[index]) { return false; } return backtrack(nums, index - 1, leftSum - nums[index]) || backtrack(nums, index - 1, leftSum); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值