题目描述
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。
如果 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
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/on… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
01背包问题🎒;
01背包🎒问题的特点是,每一件物品只有一个,其选择放入背包或者选择不放入背包🎒
; 题目理解:本题中strs中的每一个元素都作为一个商品;而背包🎒只有一个且容量为m和n两个维度同时满足条件下的最大容量; 因此本题为01背包问题最大解类型; 动态规划四部曲:
- 确定dp含义:
- dp[i][j]表示满足最多i个0且j个1的strs的最大子集
- 确定递推公式:
- 我们假设dp[i][j]的最近的一次+1的strs数组元素为substr,substr此时满足有x个0,y个1;
- dp[i][j]可以由dp[i-x][j-y]+1推导而来;
- 然后将上次推导的结果dp[i][j]与dp[i-m][j-n]+1进行比较;取最大值;
- 递推公式为:dp[i][j]=Math.max(dp[i][j],p[i-m][j-n]+1);
- 回想一下01背包问题的递归公式为dp[j]=Math.max(dp[j],dp[j-weight[i]]+value[i])
- 字符串substr的x和y相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])。
- dp数组初始化;
- 01背包问题🎒,物品价值不会是负数,将dp数组初始化为0即可;用于递推基础;
- 遍历顺序:
- 01背包一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
代码
/**
* @param {string[]} strs
* @param {number} m
* @param {number} n
* @return {number}
*/
var findMaxForm = function(strs, m, n) {
// 这是一道变相的01背包问题,选择或者不选择放入背包🎒
// 定义dp:dp[i][j]表示最多由i个0和j个1的子集个数;
// 此时strs中的元素相当于是物品,背包🎒容量为有i和j两个维度同时满足的作为条件;
// 确定01背包问题🎒递推公式 dp[j]=Math.max(dp[j],dp[j-wight[i]]+value[i])
// 所以此时递推公式应该为:dp[i][j]=Math.max(dp[i][j],dp[i-zeroNum][j-oneNum]+1)
// 1、统计每一个字符串元素(物品)的维度i、j容量;
let map=new Map();
for(let item of strs){
let oneNum=0;
for(let char of item){
if(char==='1'){
oneNum++
}
}// end of for
map.set(item,[item.length-oneNum,oneNum])
}
// 2、完成i和j两个维度容量的统计,构建dp二维数组,并进行初始化0;
const dp=new Array(m+1)
for(let i=0;i<(m+1);i++){
dp[i]=new Array(n+1).fill(0);
}
// 3、先遍历商品,再遍历容量;
const N=strs.length;
// 遍历商品
for(let i=0;i<N;i++){
// 遍历容量m、n两个维度作为容量条件;
let [v0,v1]=map.get(strs[i])
for(let j=m;j>=v0;j--){
for(let k=n;k>=v1;k--){
dp[j][k]=Math.max(dp[j][k],dp[j-v0][k-v1]+1);
}
}// end of m n
}// end of for
return dp[m][n]
};
完全背包🎒问题
【温故知新】322. 零钱兑换
动画演示-完全背包问题最小解-动态规划实现