链接:https://leetcode.cn/problems/ones-and-zeroes/solution/-by-xun-ge-v-vce6/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目
示例
思路
二维 0-1 背包问题
本题其实是01背包问题!
只不过这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品。
- 确定dp数组(dp table)以及下标的含义
dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。
- 确定递推公式
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])。
这就是一个典型的01背包! 只不过物品的重量有了两个维度而已。
- dp数组如何初始化
因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
- 确定遍历顺序
外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
那么本题也是,物品就是strs里的字符串,背包容量就是题目描述中的m和n。
代码
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int findMaxForm(char ** strs, int strsSize, int m, int n){
int dp[m+1][n+1];//定义背包大小
memset(dp, 0, sizeof(int) * (m+1) * (n+1));//初始化
for(int i = 0; i < strsSize; i++)//遍历物品
{
int oneNum = 0, zeroNum = 0;
for(int m = 0; m < strlen(strs[i]); m++)//将物品转换为具体
{
if(strs[i][m] == '0') zeroNum++;
else oneNum++;
}
for(int j = m; j >= zeroNum; j--)//更新背包情况
{
for(int i = n; i >= oneNum; i--)
{
dp[j][i] = MAX(dp[j][i], dp[j - zeroNum][i - oneNum] + 1);
}
}
}
return dp[m][n];
}
作者:xun-ge-v
链接:https://leetcode.cn/problems/ones-and-zeroes/solution/-by-xun-ge-v-vce6/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。