474. 一和零
题目链接:
给你一个二进制字符串数组 strs
和两个整数 m
和 n
。
请你找出并返回 strs
的最大子集的长度,该子集中 最多 有 m
个 0
和 n
个 1
。
如果 x
的所有元素也是 y
的元素,集合 x
是集合 y
的 子集 。
输入: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
的个数。
-
确定dp数组以及其下标的含义
该题的dp数组是一个二维数组(是因为物品的重量有两个维度,本质还是
dp[i][j]
表示最多有i
个0
和j
个1
的strs
的最大子集的长度。 -
确定递推公式
-
当物品
[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)
-
-
dp数组的初始化
与
-
确定遍历顺序
先遍历物品,后遍历背包容量并且是从后向前遍历。
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的个数
-