题目描述
思路解析动画文字版
挑子集有 2ⁿ 种,逐个算和再看是不是 11,指数级爆炸。痛点在于:很多子集只是差一个数,前面累加的和却被从头重算了一遍——同样的部分和被反复求。
为什么能用 0-1 背包?因为每个数只有「选或不选」两种,恰好对应背包里物品取一次。用一排布尔 dp[j] 记「能不能凑出和 j」:dp[0]=真(什么都不选就是 0)。每来一个数 num,从大到小扫容量更新 dp[j] = dp[j] 或 dp[j−num]——把「凑过的和记下来,不重算」。最后看 dp[11]。
建表 · dp[0]=✓:表头是目标和 0~11,每格是「能否凑出这个和」。dp[0]=✓(凑 0 肯定行,啥都不选),其余先全 ✗。下面把 nums 里的数 1、5、11、5 一个一个拿进来更新。
拿数字 1:拿数字 1,从大到小扫容量。只有 dp[1] 能更新:它的依赖格是 dp[1−1]=dp[0]=✓,于是 dp[1] 变 ✓。现在能凑出的和是 {0, 1}。
拿数字 5 · 大容量先空扫:换数字 5,从大到小先扫到 dp[11]:它的依赖格 dp[11−5]=dp[6]现在还是 ✗,所以 dp[11] 这轮没法变真。dp[10]、dp[9]…一路往下也都因依赖格还空着保持 ✗。继续往小扫,看哪格的依赖格已经是 ✓。
拿数字 5 · 填 dp[6]:换数字 5,从大到小扫。先看 dp[6]:它的依赖格 dp[6−5]=dp[1]=✓,意思是「先凑出 1,再加这个 5」,所以 dp[6] 变 ✓。为什么从大到小?这样 dp[1] 还是「没用过 5」的旧值,保证这个 5 只被用一次。
拿数字 5 · 填 dp[5]:继续往小扫到 dp[5]:依赖格 dp[5−5]=dp[0]=✓(单独选这个 5),dp[5] 变 ✓。这个 5 处理完,能凑出的和扩到 {0, 1, 5, 6}。
拿数字 5 · 负例 dp[3]:负例:扫到容量 3 时,3 比这个数 5 还小,5 根本装不下。这种格子直接沿用原值不动(dp[3] 还是 ✗)——代码里就是内层循环只扫到 num 为止,比 num 小的容量不碰。
拿数字 11 · 命中:拿数字 11,从大到小第一个就是 dp[11]:依赖格 dp[11−11]=dp[0]=✓,相当于「单独选这个 11」就凑满了!dp[11] 变 ✓,目标已经命中。
结论 · 看 dp[11]:看最后一格 dp[11]=✓:能凑出和为 11 的子集,数组可以平分,返回 true。最后那个 5 还没轮到处理就已经成功了。
「每个物品选或不选、容量恰好或不超」就是 0-1 背包。可行性用「或」、计数用「加」、最值用「max」,骨架全一样。
迁移阶梯:把这题练到能复述后,再去同类题里迁移:可行性「或」换成计数「加」就是 LC494 目标和;换成 max 装满价值就是经典 0-1 背包。状态定义复用,只改「合并」那一步。
边界三连:边界三连:极端输入先过一遍。
几个高频追问,记住答法。
参考代码
class Solution: def canPartition(self, nums): total = sum(nums) if total % 2: return False target = total // 2 dp = [False] * (target + 1) dp[0] = True for x in nums: for s in range(target, x - 1, -1): dp[s] = dp[s] or dp[s - x] return dp[target]复杂度
- 时间复杂度:O(n × target),n 个数,每个数扫一遍容量 target
- 空间复杂度:O(target),只用一行长度 target+1 的 dp
可套用的代码模板
三语言同一副骨架:一维 dp、外层枚举物品、内层容量从大到小。把「合并」换成 或/加/max 就分别是可行性/计数/最值;从大到小=每个物品只用一次(0-1),改成从小到大就成了可重复用的完全背包。本题里 W=target、合并=或、初值=False。
# 0-1 背包通用骨架:每个物品最多选一次dp = [初值] * (W + 1)dp[0] = 基准值for x in items: # 外层枚举物品 for j in range(W, x - 1, -1): # 内层容量必须从大到小! dp[j] = 合并(dp[j], dp[j - x]) # 或 / 加 / maxreturn dp[W]易错点
面试追问把动画讲成自己的话
追问为什么是 0/1 背包?
追问内层循环为什么倒序?
追问复杂度?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
不同的二叉搜索树
LeetCode 96 · 中等 · 沿着 一维动态规划 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题