§1
题目描述
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
strs,m,n = ["10","0001","111001","1","0"],5,3
输出 = 4
§2
思路解析动画文字版
下面 9 步动画会按主解代码推进,而不是泛泛讲题型。
1. 看输入:DP 表跟着代码走:先把示例输入映射到代码参数:def findMaxForm(self, strs, m, n):。
2. 初始化:DP 表跟着代码走:开局只立住必要变量:dp = [[0] * (n + 1) for _ in range(m + 1)]。
3. 进入主循环:DP 表跟着代码走:主流程从这里开始:for s in strs:。
4. 判断分支:DP 表跟着代码走:题目条件落到这一行:满足条件就进入对应分支。
5. 更新状态:DP 表跟着代码走:对应代码:return dp[m][n]。这一行决定当前轮对答案有什么贡献。
6. 处理边界:DP 表跟着代码走:边界跟着代码看:dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1)。
7. 继续推进:DP 表跟着代码走:推进语句是:for s in strs:。处理过的部分不再重新枚举。
8. 准备返回:DP 表跟着代码走:到这里,dp 已经能表达题目要求。
9. 答案收束:DP 表跟着代码走:最后检查返回形态:返回值、原地修改或设计类状态,要和 LeetCode 判题方式一致。
记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
§3
参考代码
class Solution: def findMaxForm(self, strs, m, n): dp = [[0] * (n + 1) for _ in range(m + 1)] for s in strs: zeros = s.count('0') ones = len(s) - zeros for i in range(m, zeros - 1, -1): for j in range(n, ones - 1, -1): dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) return dp[m][n]看懂代码不等于写得出。盖住上面,自己默写一遍试试。卡在哪一行说不清,就点右下角问小欧。
§4
复杂度
- 时间复杂度:O(len(strs)*m*n),每个物品更新二维背包
- 空间复杂度:O(mn),二维 dp
§5
易错点
✗ 错误写法:容量正序更新
✓ 正确写法:倒序更新
每个字符串只能用一次
✗ 错误写法:只统计 1 的数量
✓ 正确写法:同时统计 0 和 1
题目有两个容量限制
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
下一题 · 动态规划套路 21/29
→最长回文子序列
LeetCode 516 · 中等 · 沿着 动态规划套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
299道动画图解
37节语音讲解
28课数据结构
¥0.27折合 / 天
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
¥99 开通年卡 →
想成体系刷透这类套路?去图解算法专题