从二维到滚动数组
最简单的0/1背包问题,用最直观的方式表示为二维:
for(int i=0;i<n;i++){
for(int j=0;j<=target;j++){
dp[i][j] = max(dp[i-1][j-weight[i]], dp[i-1][j]);
}
}
理解为每个位置是从左上单元格或者上边来的。
改成滚动数组后,只保留dp[j]背包容量,遍历的时候依然是二维,但j要从大大小遍历,原因是:
dp[ j ] 依然是由 i-1层来的,那么当我们更新dp[j]的时候,此时没更新前的 dp[j] 就是 dp[i-1][j],而我们要保证dp[j-weight[i]] 还是i-1层的,不是i层的,也就是 j - weight[i]要后更新,所以反向遍历。
leetcode 416. Partition Equal Subset Sum
Given a non-empty array nums containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Input: nums = [1,5,11,5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
把数字分成两部分,使得他们和一样,很快可以反应出就是求一部分数使得他们和为总和的一半(target)。最简单可以暴力求解,每个数都有选和不选,求解所有组合的和的可能,判断是否有无target。O(2^n)
这时候可以发现,每个数选和不选–>类似于背包问题中第 i 件物品放或者不放。
背包问题:dp[i][j] 表示到第 i 件商品,j的容量 的最大价值
本题: dp[i][j] 表示到第 i 个数字,总和为j, 可不可以刚好达到
(题目可知 j 的范围不会很大,且因为都是正整数,才可以这样操作)
最后题目的结果就是返回 dp[n-1][target]
//是否可以取一部分数字,达到总和的一半
bool canPartition(vector