c语言sscanf函数的用法是什么
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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~