474. 一和零
题目
给你一个二进制字符串数组 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
思路
因为找到最长的字符串还有0和1的个数限制,所以我们用到三维数组。dp[i][j][k]表示前i个字符串中,使用不超过j个0和k个1时的最大子集长度。遍历每个字符串,统计0和1的数量,然后遍历每个字符串所有可能的0和1的个数组合,对于每个j,k,不选就则继承前i个字符串的结果,如果当前字符串0不超过j,1不超过k,比较选与不选当前字符串的两种情况,取较大值更新dp,输出dp[s][m][n]为最终结果。
代码
class Solution {
public://统计字符串中0和1的数量vector<int> getZerosOnes(string& s){vector<int> ans(2,0);for(char c:s) ans[c-'0']++; //'0'转为0,'1'转为1return ans;}int findMaxForm(vector<string>& strs, int m, int n) {int s=strs.size();//dp[i][j][k]表示前i个字符串中,0不超过j,1不超过k的最大子集长度vector<vector<vector<int>>> dp(s+1,vector<vector<int>>(m+1,vector<int>(n+1,0))); for(int i=0;i<s;++i){vector<int> temp=getZerosOnes(strs[i]);//获取当前字符串的0和1数量int zeros = temp[0], ones = temp[1];for(int j=0;j<=m;++j){for(int k=0;k<=n;++k)//遍历所有可能的1容量{dp[i+1][j][k]=dp[i][j][k];//不选当前字符串的情况if(k>=ones && j>=zeros) //当前字符串的0和1数量不超过当前容量限制
//dp[i][j-zeros][k-ones]+1代表选择当前字符串,dp[i][j][k]代表不选当前字符串dp[i+1][j][k]=max(dp[i][j-zeros][k-ones]+1,dp[i][j][k]);}}}return dp[s][m][n];}
};