474. 一和零

474. 一和零

题目链接:474. 一和零(中等)

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

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

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

示例 1:

输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

示例 2:

输入:strs = ["10", "0", "1"], m = 1, n = 1
输出:2
解释:最大的子集是 {"0", "1"} ,所以答案是 2 。

提示:

  • 1 <= strs.length <= 600

  • 1 <= strs[i].length <= 100

  • strs[i] 仅由 '0''1' 组成

  • 1 <= m, n <= 100

解题思路

该题可以转为01背包问题。将背包看成有两个口袋,一个口袋装0,一个口袋装1,而strs中每个物品的重量有两个维度,一个重量维度是0的个数,另一个重量维度是1的个数。

  1. 确定dp数组以及其下标的含义

    该题的dp数组是一个二维数组(是因为物品的重量有两个维度,本质还是01背包中的一维数组,而不是01背包中的二维数组(此二维数组有一维表示的是背包的容量))。

    dp[i][j]表示最多有i0j1strs的最大子集的长度。

  2. 确定递推公式

    • 当物品[i][j]装不进背包时,当前的dp[i][j] = 之前的dp[i][j]

    • 当物品[i][j]装不进背包时,可以选择装或不装

      • 选择不装,当前的dp[i][j] = 之前的dp[i][j]

      • 选择装,当前的dp[i][j] = 之前的dp[i - 当前物品中0的个数][j - 当前物品中1的个数] + 1

    所以可以得到递推公式: dp[i][j] = max (dp[i][j], dp[i - 当前物品中0的个数][j - 当前物品中1的个数] + 1)

  3. dp数组的初始化

    一维01背包类似。dp[0][0] = 0(背包容量为0)。另外因为背包问题中的物品价值都为正整数,必须保证取到最大值,所以其余的dp[i][j]也都初始化为0

  4. 确定遍历顺序

    先遍历物品,后遍历背包容量并且是从后向前遍历。

C++

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        // 1.dp[i][j]表示最多有i个0和j个1的strs的最大子集的大小
        // 3.dp初始化:因为物品价值不会是负数,dp初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); // m是0的个数,n是1的个数
        // 首先遍历物品,计算每个物品中0的个数和1的个数
        for(int k = 0; k < strs.size(); k++) {
            int zeroNum = 0, oneNum = 0;
            for (char c : strs[k]) {
                if (c == '0') {
                    zeroNum++;
                } else {
                    oneNum++;
                }
            }
            // 遍历背包容量(类似于一个背包有两个小包,第一个小包装0,第二个小包装1)
            for (int i = m; i >= zeroNum; i--) {
                for (int j = n; j >= oneNum; j--) {
                    // 2.递推公式
                    dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }
};

JavaScript

/**
 * @param {string[]} strs
 * @param {number} m
 * @param {number} n
 * @return {number}
 */
var findMaxForm = function(strs, m, n) {
    const dp = Array(m + 1);
    for (let i = 0; i < m + 1; i++) {
        dp[i] = Array(n + 1).fill(0);
    }
    // 遍历物品
    for (const s of strs) {
        let zeroNum = 0,
            oneNum = 0;
        for (const c of s) {
            if (c === '0') {
                zeroNum++;
            } else {
                oneNum++;
            }
        }
        //遍历背包
        for (let i = m; i >= zeroNum; i--) {
            for (let j = n; j >= oneNum; j--) {
                dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
            }
        }
    }
    return dp[m][n];
};
  • 时间复杂度:O(k*m*n),k是strs的大小,m是题目中要求的0的个数,n是题目要求的1的个数

  • 空间复杂度:O(m*n)

posted @ 2022-03-04 11:02  wltree  阅读(26)  评论(0编辑  收藏  举报