力扣416. 分割等和子集
题目来源(力扣):
https://leetcode.cn/problems/partition-equal-subset-sum/description/
题目描述:
给你一个 只包含正整数的非空数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
基本思路:
0-1背包问题。所有数的总和为sum,设dp[i][j]表示对于前i个数是否可以组合出数字j。
递推公式
j<0时,
dp[i][j]=dp[i-1][j];
j>0时,
dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i]]);
初始化:
初始化dp数组的第一行和第一列,
第一行,即对于第0个数nums[0],dp[0][nums[0]]=1;
第一列,即无论i为多少,当总和j为0时,一定有dp[i][0]=1;
代码实现:
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
int len = nums.size();
for (int i : nums)
sum += i;
// 0.特判,如果总和不是偶数,直接退出
if (sum % 2)
return 0;
// 1.确定dp数组及其含义 dp[i][j]表示前i个数是否能组合成数字j
bool dp[203][20003] = {0};
// 2.确定递推关系
// dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i]]&&1);
// 3.初始化 第一列,dp[i][0]=1;第一行,dp[0][nums[0]]=1
for (int i = 0; i < len; i++)
dp[i][0] = 1;
dp[0][nums[0]] = 1;
// 4.确定遍历顺序 从上往下,从左往右
for (int i = 1; i < len; i++) {
for (int j = 0; j <= sum / 2; j++) {
if (j < nums[i])
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]]);
}
}
// for (int i = 1; i < len; i++) { //或者从上往下,从右往左 也可以
// for (int j = sum / 2; j >= 0; j--) {
// if (j < nums[i])
// dp[i][j] = dp[i - 1][j];
// else
// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]]);
// }
// }
// for (int j = 0; j <= sum / 2; j++) { //或者从左往右,从上往下 也可以
// for (int i = 1; i < len; i++) {
// if (j < nums[i])
// dp[i][j] = dp[i - 1][j];
// else
// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]]);
// }
// }
// 5.打印部分数组以确定是否符合预期
// for(int j=0;j<=sum/2;j++)
// cout<<dp[len-1][j]<<" ";
// cout<<endl;
return dp[len - 1][sum / 2];
}
};
时间复杂度
O(n*sum) 其中n为数的个数,sum为所有数的总和
补充-一维dp
可以将二维dp压缩为1维
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
int len = nums.size();
for (int i : nums)
sum += i;
// 0.特判,如果总和不是偶数,直接退出
if (sum % 2)
return 0;
// 1.确定dp数组及其含义 dp[i][j]表示前i个数是否能组合成数字j
bool dp[20003] = {0};
// 2.确定递推关系
// dp[j]=max(dp[j],dp[j-nums[i]]&&1);
// 3.初始化 第一行,dp[0]=dp[nums[0]]=1
dp[0]=1;
dp[nums[0]] = 1;
// 4.确定遍历顺序 从上往下,从右往左
for (int i = 1; i < len; i++) {
for (int j = sum/2; j >= nums[i]; j--) {
dp[j]=max(dp[j],dp[j-nums[i]]&&1);
}
}
// 5.打印部分数组以确定是否符合预期
// for(int j=0;j<=sum/2;j++)
// cout<<dp[j]<<" ";
// cout<<endl;
return dp[sum / 2];
}
};
浙公网安备 33010602011771号