讲解
1. 二维背包问题
视频解析说的很好
dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
w
e
i
g
h
t
[
i
]
]
+
v
a
l
u
e
[
i
]
)
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
dp[i][j]=max(dp[i−1][j],dp[i−1][j−weight[i]]+value[i]);
2. 一维背包问题
dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。文字解析
二维: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] ) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]) dp[i][j]=max(dp[i−1][j],dp[i−1][j−weight[i]]+value[i]);
一维:
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
j
−
w
e
i
g
h
t
[
i
]
]
+
v
a
l
u
e
[
i
]
)
;
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
dp[j]=max(dp[j],dp[j−weight[i]]+value[i]);
416. 分割等和子集
只有把这个包装满,才算true, 包的容量是sum/2 ,所以有两种情况,选不选当前商品
dp[i][j]表示从数组的 [0, i] 这个子区间内挑选一些正整数 , 每个数只能用一次,使得这些数的和恰好等于 j。
- dp[i - 1][j]表示该物品不放入背包,如果在 [0, i - 1] 这个子区间内已经有一部分元素,使得它们的和为 j ,那么 dp[i][j] = true;
- dp[i - 1][j - nums[i]]表示该物品放入背包。如果在 [0, i - 1] 这个子区间内就得找到一部分元素,使得它们的和为 j - nums[i]。
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
∣
∣
d
p
[
i
−
1
]
[
j
−
n
u
m
s
[
i
]
]
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]
dp[i][j]=dp[i−1][j]∣∣dp[i−1][j−nums[i]];
就是dp[3][11] 里面装的11,那对应的dp[i - 1][j - nums[i]] = dp[2][6]也装满了,就是【1,5,5】
class Solution {
public boolean canPartition(int[] nums) {
if(nums ==null || nums.length ==0) return false;
int sum =0;
for(int num :nums){
sum +=num;
}
if(sum%2 != 0) return false;
//开始背包问题, 包的容量是11
sum = sum/2;
boolean[] dp = new boolean[sum+1];
dp[0] =true;
for(int num :nums){
for(int i= sum;i>=num;i--){
dp[i] = dp[i]||dp[i-num];
}
}
return dp[sum];
}
}
关键点:这道题要倒着写
初始化:dp[0] = true;
n
u
m
<
=
i
<
=
s
u
m
num<= i <= sum
num<=i<=sum
dp[i]表示当前背包容量为
i
i
i,是否能够被填满
- 按照数组元素遍历,不选当前的元素,就还是dp[i]
- 将当前元素加入背包,那么dp[i-num],加入了之后,剩余容量中是否能装下前面的遍历的物品(所以才是倒序的)
完全就是背包问题:
class Solution {
public boolean canPartition(int[] nums) {
int sum = Arrays.stream(nums).sum();
int n = nums.length;
if(sum%2!=0){
return false;
}
int half = sum/2;
int[] dp = new int[half+1];
for(int i=0;i<n;i++){
for(int j =half;j>=nums[i];j--){
dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
return dp[half] == half;
}
}