分割等和子集
Problem: 416. 分割等和子集
思路
我选择使用动态规划的方法来解题。我们需要判断是否可以将数组分割成两个子集,使得这两个子集的和相等。这个问题可以转化为在数组中找到一个子集,使得其和等于数组总和的一半。
解题过程
- 首先,我们计算数组的总和
total
。如果total
是奇数,那么我们无法将其分成两个和相等的子集,因此直接返回False
。 - 接下来,我们将目标和
target
定为total // 2
。 - 初始化一个二维布尔数组
dp
,其中dp[i][j]
表示前i
个元素是否可以组成和为j
的子集。 - 设置初始条件:
dp[i][0]
为True
,因为和为0
的子集总是可以通过不选取任何元素来实现。 - 遍历数组,更新
dp
数组:- 如果当前元素
nums[i]
小于等于目标和j
,则dp[i][j]
可以由两种情况得到:不包含当前元素(即dp[i-1][j]
)或包含当前元素(即dp[i-1][j-nums[i]]
)。 - 如果当前元素
nums[i]
大于目标和j
,则dp[i][j]
只能由不包含当前元素的情况得到,即dp[i-1][j]
。
- 如果当前元素
- 最后,检查
dp[n-1][target]
的值,判断是否可以将数组分割成两个和相等的子集。
复杂度
- 时间复杂度:,其中
n
是数组的长度,target
是数组总和的一半。 - 空间复杂度: ,因为使用了一个二维数组
dp
。
Code
from typing import List
class Solution:
def canPartition(self, nums: List[int]) -> bool:
n = len(nums)
if n < 2:
return False
total = sum(nums)
if total & 1:
return False
target = total // 2
if max(nums) > target:
return False
dp = [[False] * (target + 1) for _ in range(n)]
for i in range(n):
dp[i][0] = True
dp[0][nums[0]] = True
for i in range(1, n):
for j in range(1, target + 1):
if j >= nums[i]:
dp[i][j] = dp[i-1][j] | dp[i-1][j-nums[i]]
else:
dp[i][j] = dp[i-1][j]
return dp[n-1][target]