目录
题目:
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个
子集,使得两个子集的元素和相等
思路:
把01背包问题套到本题上来。背包的体积为sum / 2;背包如果正好装满,说明找到了总和为 sum / 2 的子集。背包中每一个元素是不可重复放入。
然后用动态规划。
方法一:
dp[i][j]表示第0到i个元素中能否选到和等于j的元素。
递推的想法是dp[i][j]=dp[i-1][j] || dp[i-1][j-nums[i]];
class Solution {
public boolean canPartition(int[] nums) {
if(nums==null)return false;
int len=nums.length;
int sum=0;
for(int i=0;i<len;i++){
sum+=nums[i];
}
if(sum%2==1)return false;
int target=sum/2;
boolean[][] dp=new boolean[len][target+1];
//初始化
for(int j=0;j<=target;j++){
if(nums[0]==j){
dp[0][j]=true;
}else{
dp[0][j]=false;
}
}
//动态规划遍历
for(int i=1;i<len;i++){
for(int j=0;j<=target;j++){
if(nums[i]>j){
dp[i][j]=dp[i-1][j];
}else{
dp[i][j]=dp[i-1][j] || dp[i-1][j-nums[i]];
}
}
if(dp[i][target])return true;
}
return dp[len-1][target];
}
}
方法二:
法一基础上换为一维滚动优化
class Solution {
public boolean canPartition(int[] nums) {
if(nums==null)return false;
int len=nums.length;
int sum=0;
for(int i=0;i<len;i++){
sum+=nums[i];
}
if(sum%2==1)return false;
int target=sum/2;
boolean[] dp=new boolean[target+1];
//初始化
for(int j=0;j<=target;j++){
if(nums[0]==j){
dp[j]=true;
}else{
dp[j]=false;
}
}
//动态规划遍历
for(int i=1;i<len;i++){
for(int j=target;j>=0;j--){
if(nums[i]<j){
dp[j]=dp[j] || dp[j-nums[i]];
}
}
if(dp[target])return true;
}
return dp[target];
}
}
方法三:
dp[i][j]表示j容量背包下,第0到i个元素中选到的装进背包元素最大的和。(这个和肯定小于等于j,因为是在j容量下的)
递推的想法是dp[i][j]=max(dp[i-1][j] , dp[i-1][j-nums[i]]+nums[i]);
class Solution {
public boolean canPartition(int[] nums) {
if(nums==null)return false;
int len=nums.length;
int sum=0;
for(int i=0;i<len;i++){
sum+=nums[i];
}
if(sum%2==1)return false;
int target=sum/2;
int[][] dp=new int[len][target+1];
//初始化
for(int j=nums[0];j<=target;j++){
dp[0][j]=nums[0];
}
//动态规划遍历
for(int i=1;i<len;i++){
for(int j=0;j<=target;j++){
if(nums[i]>j){
dp[i][j]=dp[i-1][j];
}else{
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i]);
}
}
if(dp[i][target]==target)return true;
}
return dp[len-1][target]==target;
}
}
方法四:
法三基础上换为一维滚动优化
class Solution {
public boolean canPartition(int[] nums) {
if(nums==null)return false;
int len=nums.length;
int sum=0;
for(int i=0;i<len;i++){
sum+=nums[i];
}
if(sum%2==1)return false;
int target=sum/2;
int[] dp=new int[target+1];
//初始化
for(int j=nums[0];j<=target;j++){
dp[j]=nums[0];
}
//动态规划遍历
for(int i=1;i<len;i++){
for(int j=target;j>=0;j--){
if(nums[i]<j){
dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
if(dp[target]==target)return true;
}
return dp[target]==target;
}
}