在本题中,我们是要把一个数组,分割成两个子集,并且两个子集的元素和相等。那么也就是说,两个子集的和是相等的,并且都是整个数组的一半。那我们考虑这是一个01背包问题,物品的价值和物品的质量一样,就是数组的元素。我们把这个数组的元素放入容量为数组和一半的背包中,如果能刚好放下,则证明可以分割,如果不可以,则证明分割不了。所以我们采用动态规划来做。
抽象成背包问题之后,直接套用背包公式的模板。本题采用一维数组来做。
dp[j]表示容量为j的背包它的价值为dp[j]。
递推公式就是dp[j] = Math.max(dp[j],dp[j-weight[i]+values[i]])。此时weight[]与values[]都一样,就是nums[]
初始化我们要考虑,我们取的是最大值,也就是每次递推,我们取两个元素的最大值,dp[0]表示容量为0,此时价值也为0;其他位置,我们也取0即可,在正整数取最大值的时候可以直接覆盖。
遍历顺序:01背包一维数组遍历顺序应该先遍历物品,再遍历背包,并且背包需要倒叙遍历。
遍历数组
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]);}//剪枝一下,每一次完成內層的for-loop,立即檢查是否dp[target] == target,優化時間複雜度(26ms -> 20ms)if(dp[target] == target)return true;}return false;}
}