Leetcode - 一和零

168 阅读2分钟

这是我参与更文挑战的第5天,活动详情查看更文挑战

题目描述

You are given an array of binary strings strs and two integers m and n.

Return the size of the largest subset of strs such that there are at most m 0's and n 1's in the subset.

A set x is a subset of a set y if all elements of x are also elements of y.

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

请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。

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

Example 1:

Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3
Output: 4
Explanation: The largest subset with at most 5 0's and 3 1's is {"10", "0001", "1", "0"}, so the answer is 4.
Other valid but smaller subsets include {"0001", "1"} and {"10", "1", "0"}.
{"111001"} is an invalid subset because it contains 4 1's, greater than the maximum of 3.

Example 2:

Input: strs = ["10","0","1"], m = 1, n = 1
Output: 2
Explanation: The largest subset is {"0", "1"}, so the answer is 2.

Constraints:

  • 1 \le strs.length \le 600
  • 1 \le strs[i].length \le 100
  • strs[i] consists only of digits '0' and '1'.
  • 1 \le m, n \le 100

解题思路

这道题和经典的背包问题非常相似,但是和经典的背包问题只有一种容量不同,这道题有两种容量,即选取的字符串子集中的 0011 的数量上限。

经典的背包问题可以使用二维动态规划求解,两个维度分别是物品和容量。这道题有两种容量,因此需要使用三维动态规划求解,三个维度分别是字符串、00 的容量和 11 的容量。

定义三维数组 dpdp,其中 dp[i][j][k]dp[i][j][k] 表示在前 ii 个字符串中,使用 jj00kk11 的情况下最多可以得到的字符串数量。假设数组 strs 的长度为 ll,则最终答案为 dp[l][m][n]dp[l][m][n]

当没有任何字符串可以使用时,可以得到的字符串数量只能是 00,因此动态规划的边界条件是:当 i=0i=0时,对任意 0jm0≤\le j \le m0kn0 \le k \le n,都有 dp[i][j][k]=0dp[i][j][k]=0

1il1\le i \le l 时,对于 strs 中的第 ii 个字符串(计数从 11 开始),首先遍历该字符串得到其中的 0011 的数量,分别记为 zerosones,然后对于 0jm0 \le j \le m0kn0 \le k \le n,计算 dp[i][j][k]dp[i][j][k]的值。

0011 的容量分别是 jjkk 时,考虑以下两种情况:

如果 j<zerosj<zerosk<onesk<ones,则不能选第 ii 个字符串,此时有 dp[i][j][k]=dp[i1][j][k]dp[i][j][k]=dp[i−1][j][k]

如果 jzerosj\ge zeroskonesk \ge ones,则如果不选第 ii 个字符串,有 dp[i][j][k]=dp[i1][j][k]dp[i][j][k]=dp[i−1][j][k],如果选第 ii 个字符串,有 dp[i][j][k]=dp[i1][jzeros][kones]+1dp[i][j][k]=dp[i−1][j−zeros][k−ones]+1dp[i][j][k]dp[i][j][k] 的值应取上面两项中的最大值。

代码

C++代码

class Solution {
public:
    vector<int> getZerosOnes(string& str) {
        vector<int> zerosOnes(2);
        int length = str.length();
        for (int i = 0; i < length; i++) {
            zerosOnes[str[i] - '0']++;
        }
        return zerosOnes;
    }

    int findMaxForm(vector<string>& strs, int m, int n) {
        int length = strs.size();
        vector<vector<vector<int>>> dp(length + 1, vector<vector<int>>(m + 1, vector<int>(n + 1)));
        for (int i = 1; i <= length; i++) {
            vector<int>&& zerosOnes = getZerosOnes(strs[i - 1]);
            int zeros = zerosOnes[0], ones = zerosOnes[1];
            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 >= zeros && k >= ones) {
                        dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - zeros][k - ones] + 1);
                    }
                }
            }
        }
        return dp[length][m][n];
    }
};