474. 一和零
思路:
第一次做01背包的题,但这类问题的状态转移方程的核心比较类似,都是 dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]),这个状态转移方程可以去看专门的01背包解析获得更好的理解。那么对于01背包问题,更多的是如何转化成01背包的问题来求解,然后就直接上状态转移方程即可。
这道题要求在m个0以下,n个1以下的最大str子集,那么这里背包问题的背包容量上限就由m和n共同决定。因为子集每次获得数加1,那么该问题的状态转移方程为:dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-zeros][k-ones]+1).
那么就算出strs数组里面每个元素的0和1的个数,然后三重for循环遍历i j k,赋值就判断当前的j是否大于当前0的个数并且k是否大于当前1的个数,如果满足说明有足够的容量装新的一个子集,那么就+1即可。否则就等于dp[i-1][j][k]
代码:
class Solution {
public:
vector<int> getZeroOne(string& str){
vector<int> zerosones(2);
for(int i=0;i<str.length();++i){
zerosones[str[i]-'0']++;
}
return zerosones;
}
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){
vector<int> zerosones = getZeroOne(strs[i-1]);
int zn = zerosones[0],on = zerosones[1];
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>=zn&&k>=on){
dp[i][j][k] = max(dp[i-1][j-zn][k-on]+1,dp[i][j][k]);
}
}
}
}
return dp[len][m][n];
}
};