1. 程式人生 > 其它 >C語言重構【474】一和零

C語言重構【474】一和零

技術標籤:# 演算法練習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 解釋:最多有 5031 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 其他滿足題意但較小的子集包括 {"0001","1"}{"10","1","0"}{"111001"} 不滿足題意,因為它含 41 ,大於 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)