LeetCode 474. 一和零

题目

分析

本题是两维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 };
原文地址:https://www.cnblogs.com/fresh-coder/p/14404977.html