474. Ones and Zeroes

问题:

给定一组只包含'0' '1' 的字符串,给定两个正整数m和n,问,要使用m个'0' n个'1',能最多构成多少个给出字符串组中的字符串。

Example 1:
Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3
Output: 4
Explanation: This are totally 4 strings can be formed by the using of 5 0s and 3 1s, which are "10","0001","1","0".

Example 2:
Input: strs = ["10","0","1"], m = 1, n = 1
Output: 2
Explanation: You could form "10", but then you'd have nothing left. Better form "0" and "1".
 
Constraints:
1 <= strs.length <= 600
1 <= strs[i].length <= 100
strs[i] consists only of digits '0' and '1'.
1 <= m, n <= 100

  

解法:DP(动态规划)  0-1 knapsack problem(0-1背包问题)

1.确定【状态】:

  • 可选择的元素:前 i 个字符串
  • 和:
    • m:m个 ' 0 '
    • n:n个 ' 1 '

2.确定【选择】:

  • 选择当前的字符串strs[i]
  • 不选择当前的字符串strs[i]

3. dp[i][m][n]的含义:

前 i 个字符串中,用m个'0' n个'1' 最多能组成的字符串个数。

4. 状态转移:

dp[i][m][n]= OR {

  • 选择 strs[i]:dp[i-1][m-strs[i].count('0')][n-strs[i].count('1')] + 1:=前 i-1 个元素中,用M个'0'N个'1'最多可组成的字符串个数 + strs[i]自己一个。(M= m-strs[i].count('0');  N= n-strs[i].count('1'))
  • 不选择 strs[i]:dp[i-1][m][n]:=前 i-1 个元素中,用m个'0'n个'1'最多可组成的字符串个数。

}

5. base case:

  • dp[0][m][n]=0
  • dp[i][0][0]=0

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][m][n]:in first i strs, the max number of strs can be formed by m 0s and n 1s.
 4     //case_1.select strs[i]    : = dp[i-1][m-strs[i].count('0')][n-strs[i].count('1')]+1
 5     //case_2.not select strs[i]: = dp[i-1][m][n]
 6     //dp[i][m][n] = max(case_1, case_2)
 7     //base: dp[0][m][n]=0
 8     //dp[i][0][0]=0
 9     int findMaxForm(vector<string>& strs, int m, int n) {
10         vector<vector<vector<int>>> dp(strs.size()+1, vector<vector<int>>(m+1, vector<int>(n+1, 0)));
11         for(int i=1; i<=strs.size(); i++) {
12             int cout_1 = count(strs[i-1].begin(), strs[i-1].end(), '1');
13             int cout_0 = count(strs[i-1].begin(), strs[i-1].end(), '0');
14             for(int M=0; M<=m; M++) {
15                 for(int N=0; N<=n; N++) {
16                     if(M-cout_0>=0 && N-cout_1>=0) {
17                         dp[i][M][N] = max(dp[i-1][M-cout_0][N-cout_1]+1, dp[i-1][M][N]);
18                     } else {
19                         dp[i][M][N] = dp[i-1][M][N];
20                     }
21                 }
22             }
23         }
24         return dp[strs.size()][m][n];
25     }
26 };

♻️ 优化:空间复杂度:3维->2维

去掉 i 

将 m和n 倒序遍历。

理由参考:https://www.cnblogs.com/habibah-chang/p/13581649.html

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][m][n]:in first i strs, the max number of strs can be formed by m 0s and n 1s.
 4     //case_1.select strs[i]    : = dp[i-1][m-strs[i].count('0')][n-strs[i].count('1')]+1
 5     //case_2.not select strs[i]: = dp[i-1][m][n]
 6     //dp[i][m][n] = max(case_1, case_2)
 7     //base: dp[0][m][n]=0
 8     //dp[i][0][0]=0
 9     int findMaxForm(vector<string>& strs, int m, int n) {
10         vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
11         for(int i=1; i<=strs.size(); i++) {
12             int cout_1 = count(strs[i-1].begin(), strs[i-1].end(), '1');
13             int cout_0 = count(strs[i-1].begin(), strs[i-1].end(), '0');
14             for(int M=m; M>=0; M--) {
15                 for(int N=n; N>=0; N--) {
16                     if(M-cout_0>=0 && N-cout_1>=0) {
17                         dp[M][N] = max(dp[M-cout_0][N-cout_1]+1, dp[M][N]);
18                     }
19                 }
20             }
21         }
22         return dp[m][n];
23     }
24 };
原文地址:https://www.cnblogs.com/habibah-chang/p/13582663.html