474. 一和零
题目来源(力扣):
https://leetcode.cn/problems/ones-and-zeroes/description/
题目描述:
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
基本思路:
其实就是一个0-1背包问题,每个物品的价值都为1,每个物品的质量分为2个维度,即字符串中"0"的数量和"1"的数量。
因此设数组dp[i][j][k]表示对于前i个数,背包1(存放"1")的容量为j,背包2(存放"0")的容量为k时,所取得的最大价值(字符串个数)为dp[i][j][k].
代码实现:
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
int dp[603][103][103] = {0};
int a[603] = {0}, b[603] = {0}; // 记录每个字符串中0、1的个数
int len = strs.size();
// 0.预处理
for (int i = 0; i < len; i++) {
for (int j = 0; j < strs[i].size(); j++) {
if (strs[i][j] == '0') {
a[i]++;
} else
b[i]++;
}
}
// 1.确定dp数组及其含义
// dp[i][j][k]
// 对于前i个字符串,当剩余可取1的个数为j可取0的个数为k时,最大的子集个数
// 2.递推公式
// dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-a[i]][k-b[i]]+1);
// 3.初始化
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= n; k++) {
if (j >= a[0] && k >= b[0])
dp[0][j][k] = 1;
}
}
// 4.确定遍历顺序
// 从前往后
for (int i = 1; i < len; i++) {
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= n; k++) {
if (j >= a[i] && k >= b[i])
dp[i][j][k] = max(dp[i - 1][j][k],
dp[i - 1][j - a[i]][k - b[i]] + 1);
else
dp[i][j][k] = dp[i - 1][j][k];
}
}
}
// 5.打印部分数据以确定是否符合预期
// for(int i=0;i<len;i++){
// for(int j=0;j<=m;j++){
// for(int k=0;k<=n;k++){
// cout<<dp[i][j][k]<<" ";
// }
// cout<<endl;
// }
// cout<<endl;
// }
return dp[len - 1][m][n];
}
};
时间复杂度
O(n)
浙公网安备 33010602011771号