416. 分割等和子集
难度中等537收藏分享切换为英文接收动态反馈
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
- 每个数组中的元素不会超过 100
- 数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
思路:我们可以巧妙的将问题转化为0-1背包问题(即和的一半的大小最多能拿到多大的值)
package LeetCode;
/**
* @ClassName Q416
* @Description TODO
* @Author m
* @Version 1.0
*/
public class Q416 {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if((sum & 1) == 1) {
return false;
}
int target = sum/2;
/**
* dp[i][j]表示0~i的数中是否能选出一定的数和为j
* 则结果即为dp[nums.length-1][target]
*/
boolean[][] dp = new boolean[nums.length][target+1];
for (int i = 0; i < dp.length; i++) {
dp[i][0] = true;
}
if(nums[0] <= target){
dp[0][nums[0]] = true;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[i].length; j++) {
//可以发现这里的dp[i][j]只与上一层有关,可以将空间复杂度优化为O(target)
dp[i][j] = dp[i-1][j];
if(nums[i] <= j) {
dp[i][j] |= dp[i-1][j-nums[i]];
}
}
}
return dp[nums.length-1][target];
}
public static void main(String[] args) {
System.out.println(new Q416().canPartition(new int[]{
100
}));
}
}