leetcode474. 一和零
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/ones-and-zeroes
题目描述
给你一个二进制字符串数组 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 。
解题思路
这个题还是背包问题,每次都是两个选择,选或者不选,只不过这题扩展的一点是。选择后重量是有两个维度,但解题框架是一样的,
process(不选)
process(选)
然后两种情况求最值。
解法一 递归加缓存
/**
* 一和零
* @param strs
* @param m
* @param n
* @return
*/
public int findMaxForm(String[] strs, int m, int n) {
int L = strs.length;
int[][][]dp = new int[m + 1][n + 1][L + 1];
return process(strs,m,n,0,dp);
}
/**
* 递归加缓存
* @param strs
* @param m
* @param n
* @param index
* @param dp
* @return
*/
public int process(String[]strs,int m,int n,int index,int[][][]dp){
//base case 就没法选了,返回0
if (index >= strs.length){
return 0;
}
//超过 越界 返回0
if (m < 0 || n < 0){
return 0;
}
//从缓存中拿
if(dp[m][n][index] != 0){
return dp[m][n][index];
}
//0的数量
int zeroNum = getZeroNum(strs[index]);
//1的数量
int oneNum = strs[index].length() - zeroNum;
//不选的时候
int p1 = process(strs,m,n,index + 1,dp);
int p2 = 0;
//选择的时候
if(m - zeroNum >= 0&& n - oneNum >= 0){
p2 = 1 + process(strs,m - zeroNum,n - oneNum,index + 1,dp);
}
dp[m][n][index] = Math.max(p1,p2);
return Math.max(p1,p2);
}
/**
* 计算0的数量
* @param str
* @return
*/
public int getZeroNum(String str){
if (str.length() == 0){
return 0;
}
int i = 0;
for (char c : str.toCharArray()){
if(c == '0'){
i++;
}
}
return i;
}
动态规划
碰到每个字符串时,只有选择和不选两种情况,我们要选两种情况里的最大值,可以推出下面的状态转移方程:
dp[i][j] = Math.max(dp[i][j],dp[i - zeroNum][j - one] + 1);
根据方程,可以直接写代码了。
代码演示
/**
*
* @param strs
* @param m 个 0
* @param n 个 1
* @return
*/
public int findMaxForm1(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for (String str : strs){
int zeroNum = getZeroNum(str);
int one = str.length() - zeroNum;
for (int i = m ; i >= zeroNum;i--){
for (int j = n; j >= one;j--){
dp[i][j] = Math.max(dp[i][j],dp[i - zeroNum][j - one] + 1);
}
}
}
return dp[m][n];
}