给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
动态规划,首先有一些细节的点:
- 所有的元素加起来不会超过20000
- 如果和为奇数,不可能会分成两个相同的数相加
- dp[i][j]表示:在[0,i]的区间,这个子区间内挑选一些正整数,每个数只能用一次,使得这些数的和等于 j
- 状态转移方程
- 如果不选择nums[i],在[0, i - 1]这个子区间内已经有一部分元素,使得它们的和为j ,那么dp[i][j] = true;
- 如果选择nums[i],在[0, i - 1]这个子区间内就得找到一部分元素,使得它们的和为j - nums[i] ,我既然这样写出来了,你就应该知道,这里讨论的前提条件是nums[i] <= j。
- dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i]] (j >= nums[i])
- dp[i][j] = dp[i - 1][j](j < nums[i])
代码
class Solution:
def canPartition(self, nums: List[int]) -> bool:
s = sum(nums)
if s % 2 == 1:
return False
target = int(s / 2)
dp = [[False for _ in range(target + 1)] for _ in range(len(nums))]
for i in range(len(dp[0])):
dp[0][i] = False if nums[0] != i else True
for i in range(1, len(nums)):
for j in range(target + 1):
if j >= nums[i]:
dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i]]
else:
dp[i][j] = dp[i - 1][j]
return dp[-1][-1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum