⼀和零
力扣:474. 一和零 - 力扣(LeetCode)
给你一个二进制字符串数组 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
注意:本题中strs 数组⾥的元素就是物品,每个物品都是⼀个!⽽m 和 n相当于是⼀个背包,两个维度的背包。
所以:但本题其实是01背包问题!
这不过这个背包有两个维度,⼀个是m ⼀个是n,⽽不同⻓度的字符串就是不同⼤⼩的待装物品。只不过这里的物品得继续分为'0'和'1' 的个数。
动规五部曲:
1. 确定dp数组以及下标的含义
dp[i][j]:最多有i个0和j个1的strs的最⼤⼦集的⼤⼩为dp[i][j]。
2. 确定递推公式
dp[i][j] 可以由前⼀个strs⾥的字符串推导出来,strs⾥的字符串有zeroNum个0,oneNum个1。
dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
然后我们在遍历的过程中,取dp[i][j]的最⼤值。
所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
此时⼤家可以回想⼀下01背包的递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);对⽐⼀下就会发现,字符串的zeroNum和oneNum相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])。
3. dp数组如何初始化
01背包的dp数组初始化为0就可以。因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
4. 确定遍历顺序
在之前的文章中我们每次都讲01背包为什么⼀定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!那么本题也是,物品就是strs⾥的字符串,背包容量就是题⽬描述中的m和n。
Java代码如下:
for(String a : strs){// 遍历字符确定'0','1'的个数
int get0 = 0;
int get1 = 0;
for(int i = 0; i < a.length(); i++)
if(a.charAt(i) == '0')
get0++;
else
get1++;
for(int x = m; x >= get0; x--)遍历背包从后往前
for(int y = n; y >= get1; y--)
dp[x][y] = Math.max(dp[x][y], dp[x - get0][y - get1] + 1);
}
5. 举例推导dp数组
以输⼊:["10","0001","111001","1","0"],m = 3,n = 3为例最后dp数组的状态如下所示:
如果对结果不理解,回顾一下递推公式和遍历顺序
以上分析完毕,Java代码如下:
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for(String a : strs){
int get0 = 0;
int get1 = 0;
for(int i = 0; i < a.length(); i++)
if(a.charAt(i) == '0')
get0++;
else
get1++;
for(int x = m; x >= get0; x--)
for(int y = n; y >= get1; y--)
dp[x][y] = Math.max(dp[x][y], dp[x - get0][y - get1] + 1);
}
return dp[m][n]
}
}