分割等和子集

思路:本题可以看成是0-1背包问题,给一个可装载重量为 sum / 2 的背包和 N 个物品,每个物品的重量记录在 nums 数组中,问是否在一种装法,能够恰好将背包装满?dp[i][j]表示前i个物品是否能装满容积为j的背包,当dp[i][j]为true时表示恰好可以装满。每个数都有放入背包和不放入两种情况,分析方法和0-1背包问题一样。 复杂度:时间复杂度O(n*sum)
,n是nums数组长度,sum是nums数组元素的和。空间复杂度O(n * sum),状态压缩之后是O(sum)

img.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public class Solution {
//可以看成是0-1背包问题,给一个可装载重量为 sum / 2 的背包和 N 个物品,
//每个物品的重量记录在 nums 数组中,问是否在一种装法,能够恰好将背包装满?
public boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for (int num : nums) {
sum += num;
}
if ((sum & 1) == 1) {//如果是奇数,那么分割不了,直接返回false
return false;
}

int target = sum / 2;
//dp[i][j]表示前i个物品是否能装满容积为j的背包,当dp[i][j]为true时表示恰好可以装满
//最后求的是 dp[n][sum] 表示前n个物品能否把容量为sum的背包恰好装满
//dp数组长度是n+1,而且是二维数组,第一维表示物品的索引,第二个维度表示背包大小
boolean[][] dp = new boolean[len][target + 1];
//dp数组初始化,dp[..][0] = true表示背包容量为0,这时候就已经装满了,
//dp[0][..] = false 表示没有物品,肯定装不满
for (int i = 0; i < n; i++) {
dp[i][0] = true;
}
//当 i==0 时,只有一个正整数 nums[0] 可以被选取,因此 dp[0][nums[0]]==true。
if (nums[0] <= target) {
dp[0][nums[0]] = true;
}
for (int i = 1; i < len; i++) {
for (int j = 0; j <= target; j++) {
if (nums[i] <= j) {
//dp[i - 1][j]表示不装入第i个物品
//dp[i - 1][j-num]表示装入第i个,此时需要向前看前i - 1是否能装满j-num
//和背包的区别,这里只是返回true和false 表示能否装满,不用计算价值
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
} else {
//背包容量不足 不能放入背包
//dp[i][j]取决于前i-1个物品是否能前好装满j的容量
dp[i][j] = dp[i - 1][j];
}
}

if (dp[i][target]) {
return true;
}
}
return dp[len - 1][target];
}
}

//状态压缩
public class Solution {

public boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for (int num : nums) {
sum += num;
}
if ((sum & 1) == 1) {
return false;
}

int target = sum / 2;
boolean[] dp = new boolean[target + 1];
dp[0] = true;

if (nums[0] <= target) {
dp[nums[0]] = true;
}
for (int i = 1; i < len; i++) {
for (int j = target; nums[i] <= j; j--) {
if (dp[target]) {
return true;
}
dp[j] = dp[j] || dp[j - nums[i]];
}
}
return dp[target];
}
}

参考文章

评论