【动态规划】力扣416:分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
本题等价于 0-1 背包问题,设所有数字和为 sum,目标是选取一部分物品,使得它们的总和为 sum/2。这道题不需要考虑价值,因此只需要通过一个布尔值矩阵来表示状态转移矩阵。
注意边界条件的处理:
- 根据数组的长度 n 判断数组是否可以被划分。如果 n<2,则不可能将数组分割成元素和相等的两个子集,因此直接返回 false。
- 计算整个数组的元素和 sum 。如果 sum 是奇数,则不可能将数组分割成元素和相等的两个子集,因此直接返回 false。如果 sum 是偶数,则令 target= sum/2,需要判断是否可以从数组中选出一些数字,使得这些数字的和等于 target。
- 一种取巧:找出最大元素 maxNum,如果 maxNum > target,则除了 maxNum 以外的所有元素之和一定小于 target,因此不可能将数组分割成元素和相等的两个子集,直接返回 false。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
total = sum(nums)
n = len(nums)
if total % 2 != 0 or n < 2:
return False
target = total // 2
# dp = [True] + [False] * target
dp = [False] * (target + 1)
dp[0] = True
'''
for i, num in enumerate(nums):
for j in range(target, num - 1, -1):
dp[j] |= dp[j - num]
'''
for i in range(n):
for j in range(target, nums[i - 1] - 1, -1):
dp[j] = dp[j] | dp[j - nums[i - 1]]
return dp[target]
时间复杂度:O(n×target),其中 n 是数组的长度,target 是整个数组的元素和的一半。需要计算出所有的状态,每个状态在进行转移时的时间复杂度为 O(1)。
空间复杂度:O(target),其中 target 是整个数组的元素和的一半。空间复杂度取决于 dp 数组,进行空间优化的情况下空间复杂度可以降到 O(target)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理