题目
分析
本题是两维01背包。每个子字符串为一件物品,并且只取一次,这就是01背包。两个维度体现在零的数量和一的数量上,也就是原始的01背包中的体积是一个维度,这里对应0的数量和1的数量。原始01背包中的价值对应每一个子字符串,选中子字符串就加1。dp【i】【j】表示最多i个零和最多j个1的最大集合中元素的个数。动态转移方程为:
dp[i][j] = max(dp[i][j],dp[i-zeroSum][j-oneSum]+1) 这个思想还是来源于01背包中滚动数组的转移方程。dp[i][j]的由来是从上一步来的dp[i][j] (不取这个子串)或者dp[i-zeroSum][j-oneSum]+1(取这个子串)。回顾下用滚动数组优化后的01背包的动态转移方程:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])。其实和本题本质一样,只是本题变成二维。
滚动数组初始化为0,遍历顺序为:先背包后重量,且重量倒序遍历。
对应本题:先遍历每个子字符串统计其0和1的数量,然后倒序遍历0和1的数量。
代码
1 class Solution { 2 public: 3 int findMaxForm(vector<string>& strs, int m, int n) { 4 vector<vector<int>> dp(m+1,vector<int>(n+1,0)); 5 //外层遍历背包,内层遍历容量 6 for(auto s:strs){ 7 int zeroSum = 0,oneSum = 0; 8 for(auto c:s){ 9 if(c == '0') zeroSum++; 10 if(c == '1') oneSum++; 11 } 12 for(int i = m;i >= zeroSum;i--){ 13 for(int j = n;j >=oneSum;j--){ 14 //不选或者选当前子串 15 dp[i][j] = max(dp[i][j],dp[i-zeroSum][j-oneSum]+1); 16 } 17 } 18 } 19 return dp[m][n]; 20 } 21 };