python
没看答案,暴力回溯法。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
if sum(nums) % 2 == 1:
return False
nums = sorted(nums)
target = sum(nums) // 2
sumTrack = 0
flag = False
def backtrack(start):
nonlocal sumTrack, target, flag
if flag: return
if sumTrack == target:
flag = True
return
for cho in range(start, len(nums)):
sumTrack += nums[cho]
if sumTrack <= target:
start = cho + 1
backtrack(start)
sumTrack -= nums[cho]
backtrack(0)
return flag
动态规划,可以转化为01背包问题。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
'''
根据题意可知如果能够分割,则nums的和必为偶数,且target为一个子集的和,故可转化为01背包问题:
背包容量:target
可选择的物品:数组nums的元素
物品重量:数组nums的元素值
套01背包问题的模板即可,答案是背包能否装满
'''
if sum(nums) % 2 == 1:
return False
target = sum(nums) // 2
dp = [[0] * (target+1) for _ in range(len(nums))]
for j in range(target+1):
if j >= nums[0]:
dp[0][j] = nums[0]
for i in range(len(nums)):
for j in range(1, target+1):
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]]+nums[i])
return dp[-1][-1] == target
01背包问题的二维dp数组,一般都可以替换成一维滚动数组,同样要注意背包遍历要倒序以防止重复添加物品。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
'''
01背包问题可优化二维dp数组为一维滚动dp数组
注意dp数组的遍历是从后往前的,因为可以防止物品被添加超过一次
'''
if sum(nums) % 2 == 1:
return False
nums = sorted(nums)
target = sum(nums) // 2
dp = [0] * (target+1)
for j in range(target+1):
if j >= nums[0]:
dp[j] = nums[0]
for i in range(1, len(nums)):
for j in range(target, -1, -1):
if j < nums[i]:
dp[j] = dp[j]
else:
dp[j] = max(dp[j], dp[j-nums[i]]+nums[i])
return dp[-1] == target
c++
class Solution {
public:
bool canPartition(vector<int>& nums) {
// 思路: 转化成0-1背包问题,只需要求出sum(nums)/2,再看能否装满即可
// state: dp[i]表示选择或不选择nums[i]能否凑齐背包
// basecase: dp[0]=false
// transfer: dp[j] = dp[j] || dp[j-num]; 前者为不选择nums[i], 后者为选择nums[i]
// result: dp[sum/2]
int sum = 0;
for (auto& num : nums) {
sum += num;
}
if (sum % 2 == 1) return false;
int amount = sum / 2;
vector<bool> dp(amount+1, false);
dp[0] = true;
for (auto& num : nums) {
// 这里必须倒序遍历,因为每个元素只能被选择一次(0-1背包)
// 当每个元素都可以被选择多次时,也可以正序遍历(完全背包)
for (int j = amount; j >= 1; j--) {
if (j - num >= 0) {
dp[j] = dp[j] || dp[j-num];
}
}
}
return dp[amount];
}
};