class Solution {
public:
  int findMaxForm(vector<string> &strs, int m, int n) {
    // return func1(strs, m, n);
    // return func2(strs, m, n);
    return func3(strs, m, n);
  }
  // ** recursive
  // ** time 0(len * 2^N), len = max length of strs, N = strs.size()
  int func1(vector<string> &strs, int m, int n) {
    return helper1(strs, 0, m, n);
  }
  int helper1(vector<string> &strs, int idx, int m, int n) {
    if (idx >= strs.size()) {
      return 0;
    }
    int cnt0 = 0;
    int cnt1 = 0;
    for (int i = 0; i < strs[idx].length(); i++) {
      if (strs[idx][i] == '0')
        cnt0++;
      if (strs[idx][i] == '1')
        cnt1++;
    }
    int notp = helper1(strs, idx + 1, m, n);
    int pick = notp;
    if (cnt0 <= m && cnt1 <= n) {
      pick = 1 + helper1(strs, idx + 1, m - cnt0, n - cnt1);
    }
    return max(notp, pick);
  }
  // ** dp two 2D array
  int func2(vector<string> &strs, int m, int n) {
    vector<vector<int>> dp1(m + 1, vector<int>(n + 1, 0));
    vector<vector<int>> dp2(m + 1, vector<int>(n + 1, 0));
    for (int i = 0; i < strs.size(); i++) {
      int cnt0 = 0;
      int cnt1 = 0;
      for (int j = 0; j < strs[i].length(); j++) {
        if (strs[i][j] == '0')
          cnt0++;
        if (strs[i][j] == '1')
          cnt1++;
      }
      for (int x = cnt0; x <= m; x++) {
        for (int y = cnt1; y <= n; y++) {
          dp1[x][y] = max(dp2[x][y], 1 + dp2[x - cnt0][y - cnt1]);
        }
      }
      for (int x = 0; x <= m; x++) {
        for (int y = 0; y <= n; y++) {
          dp2[x][y] = dp1[x][y];
        }
      }
      // for (int x = 0; x <= m; x++) {
      //     for (int y = 0; y <= n; y++) {
      //         cout << dp2[x][y] << " ";
      //     }
      //     cout << endl;
      // }
      // cout << "-------" << endl;
    }
    return dp1[m][n];
  }
  // ** dp one 2D array
  int func3(vector<string> &strs, int m, int n) {
    vector<vector<int>> dp1(m + 1, vector<int>(n + 1, 0));
    for (int i = 0; i < strs.size(); i++) {
      int cnt0 = 0;
      int cnt1 = 0;
      for (int j = 0; j < strs[i].length(); j++) {
        if (strs[i][j] == '0')
          cnt0++;
        if (strs[i][j] == '1')
          cnt1++;
      }
      for (int x = m; x >= cnt0; x--) {
        for (int y = n; y >= cnt1; y--) {
          dp1[x][y] = max(dp1[x][y], 1 + dp1[x - cnt0][y - cnt1]);
        }
      }
    }
    return dp1[m][n];
  }
};