1.题目解析
题目来源
474.一和零——力扣
测试用例
2.算法原理
1.状态表示
本题是一个二维费用的问题,如果一开始直接使用二维dp表来表示比较困难,所以不妨直接使用三维dp表先来理解:
dp[i][j][k]:在区间[1,i]上选择字符串,此时在字符0的总和不大于j且字符1的总和不大于k的情况下满足该条件的最长子集长度
2.状态转移方程
我们这里以第i个字符串的选择与否来写出状态转移方程
当第i个字符串不被选择:此时dp[i][j][k]=dp[i-1][j][k],因为不选择所以字符0和1的个数不变
当第i个字符串被选择:此时dp[i][j][k]=dp[i-1][j-a][k-b]+1,这里的a/b代表第i个字符串中0/1的个数,在第i个字符串被选择时要将该字符串中的字符0和1加入进dp表判断是否可以加入到子集中,可以加入就寻找前面的dp值
3.初始化
这里的初始化只需要初始化当i等于0时的情况即可,因为判断了j与k一定大于a和b,也就是一定不会越界,无需判断
当i等于0,意味着没有选择字符串,那么子集的长度一定为0,所以将第一层初始化为0即可
4.填表顺序
从前向后逐层填表,每一层从上到下,每一行从左到右
5.返回值
返回dp[len][m][n]
3.实战代码
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n)
{
int len = strs.size();
vector<vector<vector<int>>> dp(len+1,vector<vector<int>>(m+1,vector<int>(n+1)));
for(int i = 1;i <= len;i++)
{
int a = 0,b = 0;
for(auto e : strs[i-1])
{
if(e == '0')
{
a++;
}
else
{
b++;
}
}
for(int j = 0;j <= m;j++)
for(int k = 0;k <= n;k++)
{
dp[i][j][k] = dp[i-1][j][k];
if(j >= a && k >= b)
dp[i][j][k] = max(dp[i][j][k],dp[i-1][j-a][k-b] + 1);
}
}
return dp[len][m][n];
}
};
代码解析
4.代码优化
标签:初始化,int,len,二维,vector,474,字符串,动态,dp From: https://blog.csdn.net/2301_80689220/article/details/143867686