
/**
能否将数组分割为两个值相等的子集,即遍历数组得到总和totalSum,则我们需要在数组中挑选元素,使得和为totalSum / 2
canMake[i],代表能否选择元素凑出i(不可重复选择),canMake[0]初始化为true,其余默认为false
每个元素只能用一次,递推时canMake[]必须倒序遍历,正序遍历会导致元素重复使用
例子:
假如有一个钱包,钱包中有一张面额为2的纸币(只有一张不能重复使用),即num = 2
那么此时canMake[2]为true,当canMake[4]时,发现canMake[2] = true,且num = 2,那么会误认为canMake[4] = true
实际上num = 2,即面额为2的纸币在canMake[2]时已经使用过一次了,canMake[4]为false才对,正序遍历导致重复使用故而不能正序遍历
canMake[i] = canMake[i] || canMake[i - num],在凑目标值时,当前num要么使用,要么不使用
若num使用--> canMake[i - num],即若i - num可以凑出,且当前存在num可用,那么i一定能凑出
若num不适用--> canMake[i],即若不使用num只有当i已经凑出了才可以不使用num
*/
class Solution {
/**
能否将数组分割为两个值相等的子集,即遍历数组得到总和totalSum,则我们需要在数组中挑选元素,使得和为totalSum / 2
canMake[i],代表能否选择元素凑出i(不可重复选择),canMake[0]初始化为true,其余默认为false
每个元素只能用一次,递推时canMake[]必须倒序遍历,正序遍历会导致元素重复使用
例子:
假如有一个钱包,钱包中有一张面额为2的纸币(只有一张不能重复使用),即num = 2
那么此时canMake[2]为true,当canMake[4]时,发现canMake[2] = true,且num = 2,那么会误认为canMake[4] = true
实际上num = 2,即面额为2的纸币在canMake[2]时已经使用过一次了,canMake[4]为false才对,正序遍历导致重复使用故而不能正序遍历
canMake[i] = canMake[i] || canMake[i - num],在凑目标值时,当前num要么使用,要么不使用
若num使用--> canMake[i - num],即若i - num可以凑出,且当前存在num可用,那么i一定能凑出
若num不适用--> canMake[i],即若不使用num只有当i已经凑出了才可以不使用num
*/
public boolean canPartition(int[] nums) {
int totalSum = 0;
for(int num : nums) {
totalSum += num;
}
if(totalSum % 2 != 0) {
return false;
}
int target = totalSum / 2;
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for(int num : nums) {
for(int i = target; i >= num; i--) {
dp[i] = dp[i] || dp[i - num];
if(dp[target] == true) {
return true;
}
}
}
return dp[target];
}
}
7679



被折叠的 条评论
为什么被折叠?



