474. 一和零

中等 數組 字串 動態規劃

思路

相當於01背包問題,不過現在的限制不只一個,而是有兩個,一個背包放0,一個放1。 第一個方法是記憶化搜索,透過遞迴把問題拆分成更小規模的子問題。

假設 cnt1[i] 代表 strs[i] 中有多少 1cnt0[i] 代表 strs[i] 中有多少0

dfs[i][j][k]代表strs的前i個物品中,在0至多放j個,1至多放k個的情況下,最多能放下幾個物品。

要想知道dfs[i][j][k],需要考慮兩種情況

dfs[i][j][k]={:i1個物品中,限制為jcnt0[i],kcnt1[i]dfs[i1][j][k]不選:i1個物品中,限制為j,k的情況下的最佳解dfs[i1][j][k]dfs[i][j][k] = \begin{cases} \text{選}: & \text{前} i - 1 \text{個物品中,限制為} j - \text{cnt0}[i], k - \text{cnt1}[i] & dfs[i - 1][j][k]\\ \text{不選}: & \text{前}i - 1\text{個物品中,限制為}j, k\text{的情況下的最佳解} & dfs[i - 1][j][k] \end{cases}

程式碼

1. 記憶化搜索

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<int> cnt0(strs.size());
        for(int i = 0; i < strs.size(); ++i) {
            cnt0[i] = ranges::count(strs[i], '0');
        }
        // memo[k][m][n] = 前 k 個字串, strs的最大子集長度, 最多有 m 個 0 跟 n 個 1
        vector memo(strs.size(), vector<vector<int>>(m + 1, vector<int>(n + 1, -1)));
        auto dfs = [&](this auto&& dfs, int i, int j, int k) {
            if(i < 0) {
                return 0;
            }
            int& res = memo[i][j][k];
            if(res != -1) {
                return res;
            }
            res = dfs(i - 1, j, k); // 不選
            int cnt1 = strs[i].size() - cnt0[i];
            if(j >= cnt0[i] && k >= cnt1) { // 選
                res = max(res, 1 + dfs(i - 1, j - cnt0[i], k - cnt1));
            }
            return res;
        };
        return dfs(strs.size() - 1, m, n);
    }
};

2.動態規劃

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for(auto str : strs) {
            int i_min = ranges::count(str, '0');
            int j_min = str.size() - i_min;
            for(int i = m; i >= i_min; --i) {
                for(int j = n; j >= j_min; --j) {
                    dp[i][j] = max(dp[i][j], dp[i - i_min][j - j_min] + 1);
                }
            }
        }
        return dp[m][n];
    }
};

複雜度分析

  • 時間複雜度:O(mnk+L)O(mnk + L)LLstrs 中所有字串的長度和
  • 空間複雜度:方法一O(mnk)O(mnk),方法二O(mn)O(mn)

顯示設定

背景線條
顯示背景網格線條
懸停發光
滑鼠懸停時顯示霓虹效果
聚光燈
跟隨滑鼠的聚光燈效果
背景透明度
開啟透明玻璃效果
主題顏色
自訂主要顏色