416.分割等和子集
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum
1、回溯 (会超时)
class Solution {
public boolean canPartition(int[] nums) {//0-1背包问题
int sum = 0;
for (int v : nums)
sum += v;
if (sum % 2 != 0)
return false;
else{
sum /= 2;
return backtrace(nums,0,sum);
}
}
//回溯
private boolean backtrace(int[] nums,int index,int sum){
if (sum == 0)
return true;
if (sum < 0 || index == nums.length)
return false;
boolean choose = backtrace(nums,index+1,sum);
boolean unchoose = false;
if (sum >= nums[index])
unchoose = backtrace(nums,index+1,sum-nums[index]);
return choose || unchoose;
}
}
2、动态规划(0-1背包问题)
class Solution {
//算法一:回溯(会超时)
//算法二:动态规划(0-1背包问题)
public boolean canPartition(int[] nums) {
//status: 第一个集合元素和;选择:是否选入第一个集合
//dp[i][j]=x; i表示前数组下标前i个数,j表示集合元素总和
int sum = 0;
int len = nums.length;
for (int i = 0;i < len;i++)
sum += nums[i];
if (sum % 2 != 0)//
return false;
sum /= 2;
boolean[][] dp = new boolean [len+1][sum+1];
//base case
for(int i = 0 ;i <= len;i++){
dp[i][0] = true;//无论时前i个数,若集合元素和为0,全不选就是true
}
//status transfer
for (int i = 1;i <= len;i++){//依次遍历元素
for (int j = 1; j <= sum;j++){//第一个集合的元素和
if (j >= nums[i-1])
dp[i][j] = dp[i-1][j-nums[i-1]] || dp[i-1][j];
else
dp[i][j] = dp[i-1][j];
}
}
return dp[len][sum];
}
}
3、优化动态规划
dp[i][j] = dp[i-1][j-nums[i-1]] || dp[i-1][j];
注意看这个状态转移方程,发现每一次状态转移实际上只可能使用到dp[i-1][j] 或 dp[i-1][j-nums[i-1]]
,所以可以把代表数组下标i
的一个维度压缩,只表示dp[j]
class Solution {
//算法一:回溯(会超时)
//算法二:动态规划(0-1背包问题)
public boolean canPartition(int[] nums) {
//status: 第一个集合元素和;选择:是否选入第一个集合
//dp[j]=x; j表示集合元素总和
int sum = 0;
int len = nums.length;
for (int i = 0;i < len;i++)
sum += nums[i];
if (sum % 2 != 0)//
return false;
sum /= 2;
boolean[]dp = new boolean[sum+1];
//base case
dp[0] = true;//无论时前i个数,若集合元素和为0,全不选就是true
//status transfer
// Arrays.sort(nums);
for (int i = 1;i <= len;i++){//依次遍历元素
for (int j = sum; j >= 1;j--){//第一个集合的元素和,注意从j=sum 开始
if (j >= nums[i-1])
dp[j] = dp[j-nums[i-1]] || dp[j];
// else
// dp[j] = dp[j];
}
}
return dp[sum];
}
}