C語言重構【474】一和零
阿新 • • 發佈:2021-01-17
技術標籤:# 演算法練習C語言版
文章目錄
所有題目原始碼:Git地址
題目
給你一個二進位制字串陣列 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 。
方案:
- 思路在註釋中,這裡簡單講下,我認為這是一道二維動態規劃的題(雖然是三維dp陣列),其公式如下:參考地址
- 需要注意的是i=0的第一個二維一定得初始化為0,我這裡本來想用三維vector,結果不知道咋初始化~,後來還是用了原始方法
- 值得一提的是,可以先把每個字串的0,1個數事先算出來,再呼叫就可以減少很多計算量,同時也簡化了題目。
class Solution
{
public:
int findMaxForm (vector<string> &strs, int m, int n)
{
int len = strs.size();
//dp[i][j][k] i=len;j=m;k=n;
// vector<vector<vector<int>>> dp(len+1,vector<int>(m+1,vector<int>(n+1)));
int dp[len + 1][m + 1][n + 1];
for (int j = 0; j <= m; j++)
for (int k = 0; k <= n; k++)
dp[0][j][k] = 0;
//先數清每個串0,1個數
// vector<vector<int>> tmp(len,vector<int>(2,0));
int tmp[len][2];
for (int i = 0; i < len; i++)
{
//count
int cn = 0, cm = 0;
for (int j = 0; j < strs[i].size(); j++)
if (strs[i][j] == '0')
cm++;
else if (strs[i][j] == '1')
cn++;
tmp[i][0] = cm;
tmp[i][1] = cn;
}
//再填dp
//dp[i][j][k] =dp[i-1][j][k] (不放)
// =dp[i-1][j-m][k-n]+1 (放,這裡注意需要考慮jk比mn小的問題,mn是某個字串01個數)
for (int i = 1; i <= len; i++)
for (int j = 0; j <= m; j++)
for (int k = 0; k <= n; k++)
if (k < tmp[i - 1][1] || j < tmp[i - 1][0])
//揹包空間不夠,不能放
dp[i][j][k] = dp[i - 1][j][k];
else
//揹包空間足夠,可以考慮放
dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - tmp[i - 1][0]][k - tmp[i - 1][1]] + 1);
return dp[len][m][n];
}
};
複雜度計算
- 時間複雜度:O(lenmn)
- 空間複雜度:O(lenmn);其他的計數為小頭(2*len)