474. 一和零

Posted by farmer3-c on March 17, 2026

474. 一和零

给你一个二进制字符串数组 strs 和两个整数 mn

请你找出并返回 strs 的最大子集的长度,该子集中 最多m0n1

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y子集

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0' 和 '1' 组成
  • 1 <= m, n <= 100

思路

首先,这是一个二维0-1背包问题,可以使用三维数组解决。

f[i][j][k]:i代表0~i的选取结果,j代表不超过j个零,k同理。

f[i][j][k]=max(dp[i−1][j][k],dp[i−1][j−当前字符串使用0的个数][k−当前字符串使用1的个数]+1)

dp[i−1][j][k] 不选择当前考虑的字符串i

dp[i−1][j−当前字符串使用0的个数][k−当前字符串使用1的个数]+1 选择当前考虑的字符串​

初始化:为了避免分类讨论,通常多设置一行。这里可以认为,第 0 个字符串是空串。

点击展开/折叠
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        int len = strs.size();
         vector<vector<vector<int>>> dp(len + 1, vector<vector<int>>(m + 1, vector<int>(n + 1, 0)));
        for (int i = 1; i <= len; i++) {
            int x1 = cnum(strs[i - 1]);
            int x0 = strs[i - 1].size() - x1;
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k <= n; k++) {
                    dp[i][j][k] = dp[i - 1][j][k];
                    if (j >= x0 && k >= x1) {
                        dp[i][j][k] =
                            max(dp[i - 1][j][k], dp[i - 1][j - x0][k - x1] + 1);
                    }
                }
            }
        }
        return dp[len][m][n];
    }
    int cnum(string s) {
        int cnt = 0;
        for (auto c : s) {
            if (c == '1')
                cnt++;
        }
        return cnt;
    }
};

参考