LeetCode 474:一和零(Ones and Zeroes)------ 题解 ✅
🔗 题目链接
👉 https://leetcode.cn/problems/ones-and-zeroes/
📖 内容概要
给定一个二进制字符串数组 strs,以及两个整数 m 和 n,
请你找出并返回 strs 的 最大子集大小,使得子集中:
'0'的总数不超过m'1'的总数不超过n
✅ 二维 0/1 背包
✅ 字符串视为物品
✅ 面试高频 / Medium-Hard 过渡题
💡 解题思路(核心)
一、问题本质
每个字符串:
- 消耗一定数量的
0 - 消耗一定数量的
1 - 价值为
1
👉 在二维资源限制下,最多能选多少个字符串
✅ 标准的 二维 0/1 背包问题
二、状态定义
java
dp[i][j] = 使用不超过 i 个 0 和 j 个 1,能组成的最大字符串数量
三、状态转移方程
设当前字符串消耗:
x个'0'y个'1'
java
dp[i][j] = max(
dp[i][j],
dp[i - x][j - y] + 1
)
✅ 选或不选当前字符串
✅ 必须 倒序遍历(0/1 背包)
四、初始化
java
int[][] dp = new int[m + 1][n + 1];
默认值 0 即可。
✅ AC 代码(Java)
java
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for (String s : strs) {
int x = 0, y = 0;
// 统计 0 和 1 的数量
for (char c : s.toCharArray()) {
if (c == '0') x++;
else y++;
}
// 二维 0/1 背包
for (int i = m; i >= x; i--) {
for (int j = n; j >= y; j--) {
dp[i][j] = Math.max(
dp[i][j],
dp[i - x][j - y] + 1
);
}
}
}
return dp[m][n];
}
}
⏱️ 复杂度分析
| 指标 | 复杂度 |
|---|---|
| 时间复杂度 | O(k × m × n)(k 为字符串个数) |
| 空间复杂度 | O(m × n) |
🔍 与其他背包题的对比
| 题目 | 背包维度 | 物品 |
|---|---|---|
| 0/1 背包 | 一维 | 重量 |
| 分割等和子集 | 一维 | 重量 = 价值 |
| 一和零 | 二维 | (0数量, 1数量) |
✅ 一句话总结
把每个字符串看成"消耗 0 和 1 的物品",在二维背包容量下求最大个数。
📌 面试加分点(建议记住)
- ✅ 为什么是二维 DP?
- ✅ 为什么必须倒序遍历?
- ✅ 为什么价值是
1而不是字符串长度? - ✅ 与"最多硬币数"问题的相似性