分割等和子集
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 Listclass Solution:def canPartition(self, nums: List[int]) -> bool:n = len(nums)if n < 2:return Falsetotal = sum(nums)if total & 1:return Falsetarget = total // 2if max(nums) > target:return Falsedp = [[False] * (target + 1) for _ in range(n)]for i in range(n):dp[i][0] = Truedp[0][nums[0]] = Truefor 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]