leeetcode474. 一和零(二維01揹包)
連結:https://leetcode-cn.com/problems/ones-and-zeroes/
題目
給你一個二進位制字串陣列 strs 和兩個整數 m 和 n 。
請你找出並返回 strs 的最大子集的長度,該子集中 最多 有 m 個 0 和 n 個 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
示例
示例 1:
輸入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
輸出:4
解釋:最多有 5 個 0 和 3 個 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他滿足題意但較小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不滿足題意,因為它含 4 個 1 ,大於 n 的值 3 。
示例 2:
輸入:strs = ["10", "0", "1"], m = 1, n = 1
輸出:2
解釋:最大的子集是 {"0", "1"} ,所以答案是 2 。
提示:
1 <= strs.length <= 600
1 <= strs[i].length <= 100
strs[i]僅由'0' 和'1' 組成
1 <= m, n <= 100
思路
這題是標準的二維0-1揹包模板題,
在做的時候,我沒考慮到,直接按照一維揹包問題用貪心模擬了兩個維度的揹包
以0作為放入揹包的物體,然後判斷放入揹包時1的數量,如果0的數量相同且無法放入更多的0,則判定1最少情況
class Solution { public: int findMaxForm(vector<string>& strs, int m, int n) { int sn = strs.size(); vector<vector<int>>v(sn, vector<int>(2)); for (int i = 0; i<sn; i++){ int cnt0 = 0, cnt1 = 0; for (auto s : strs[i]){ if (s == '1') cnt1++; if (s == '0') cnt0++; } v[i][0] = cnt0; v[i][1] = cnt1; } sort(v.begin(), v.end(), [](vector<int>&a, vector<int>&b){return a[1] < b[1]; }); vector<vector<int>>dp0(m+1 ,vector<int>(2)); priority_queue<int>pq; int ans = 0; for (int i = 0; i < sn; i++){ vector<vector<int>>t0 = dp0; if (v[i][0] < m + 1 && v[i][1] < n + 1){ if (!dp0[v[i][0]][0]){ dp0[v[i][0]][0] = 1; dp0[v[i][0]][1] = v[i][1]; } else if (dp0[v[i][0]][0] == 1&&v[i][0]!=0){ dp0[v[i][0]][1] = min(dp0[v[i][0]][1], v[i][1]); } else if (v[i][0] == 0){ if (dp0[0][1] + v[i][1] < n + 1){ dp0[0][0] = dp0[0][0] + 1; dp0[0][1] = dp0[0][1] + v[i][1]; pq.push(v[i][1]); }else{ if (pq.top() > v[i][1]){ dp0[0][1] = dp0[0][1] - pq.top(); pq.pop(); dp0[0][1] = dp0[0][1] + v[i][1]; pq.push(v[i][1]); } } } ans = max(dp0[v[i][0]][0], ans); } for (int j = v[i][0]; j < m + 1;j++){ if (t0[j - v[i][0]][0]){ if (t0[j - v[i][0]][0] + 1 > dp0[j][0] && t0[j - v[i][0]][1] + v[i][1] < n + 1){ dp0[j][0] = t0[j - v[i][0]][0] + 1; dp0[j][1] = t0[j - v[i][0]][1] + v[i][1]; } else if (t0[j - v[i][0]][0] + 1 == dp0[j][0]){ dp0[j][1] = min(t0[j - v[i][0]][1] + v[i][1], dp0[j][1]); } } ans = max(ans, dp0[j][0]); } } return ans; } };
但實際上,只需要將將一維揹包問題擴充套件到二維,轉移方程為dp[i][j]=max(dp[i][j],dp[i-c0][j-c1]+1);
注意使用了空間壓縮後的二維揹包,需要從後往前進行遍歷,由於需要用到前置揹包的資料,所以只能先修改前部分
class Solution { public: int findMaxForm(vector<string>& strs, int m, int n) { vector<vector<int>>dp(m+1,vector<int>(n+1)); for(auto &str:strs){ int c0=count(str.begin(),str.end(),'0'),c1=count(str.begin(),str.end(),'1'); for(int i=m;i>=c0;--i){ for(int j=n;j>=c1;--j){ dp[i][j]=max(dp[i][j],dp[i-c0][j-c1]+1); } } } return dp[m][n]; } };