474. 一和零

在这里插入图片描述
dfs超时。考虑dp,三维dp,其实从本质来说还是01背包,只是要考虑的不只只是物品的重量,还有物品的大小(假设这样打比方),就是放进一个物品时,要考虑它的0和1。所以就是dp[i][j][k]表示在前i个字符串中,用j个0和k个1最多可以组成几个字符串。
每一轮计算当前字符串的0和1的个数。
状态转移:看看当前字符串取或者不取,如果取了没超的话就取dp[i][j][k] = dp[i-1][j-one][k-zero]+1
如果不取就dp[i][j][k] = dp[i-1][j][k]
可以考虑状压,详情见代码。

class Solution {
public:
    // void dfs(vector<string>& strs,int m, int n,int tmpZero,int tmpOne, int index,int num){
    //     //计算加上这个数是否正常,防止一开始进来第一个就不满足了,在main中也要for循环对每次数字开头
    //     int one = 0, zero = 0;
    //     for(char c:strs[index]){
    //         if(c == '0') zero++;
    //         if(c == '1') one++;
    //     }
    //     if(tmpOne + one >n || tmpZero + zero > m) return;
    //     res = max(res,num);
    //     tmpOne += one;
    //     tmpZero += zero;
    //     for(int i = index+1; i < strs.size(); ++i){
    //         dfs(strs,m,n,tmpZero,tmpOne,i,num+1);
    //     }
    // }
    int findMaxForm(vector<string>& strs, int m, int n) {
        //尽可能把0和1用完才能组成更多的数字
        //dfs爆搜,每次加入一个元素就计算0和1的总量是否超了,如果超了就返回如果没超就看看能否更新res
        // for(int i = 0; i < strs.size(); ++i){
        //     dfs(strs,m,n,0,0,i,1);
        // }
        // return res;

        //也是01背包,看当前数字取或者不取,dp[i][j][k]表示在前i个字符串中,用j个0和k个1最多可以组成几个字符串
        //状态转移:看看当前字符串取或者不取,如果取了没超的话就取dp[i][j][k] = dp[i-1][j-one][k-zero]+1
        //如果不取就dp[i][j][k] = dp[i-1][j][k]
        //vector<vector<vector<int>>> dp(strs.size()+1,vector<vector<int>>(m+1,vector<int>(n+1,0)));
        //basecase:当取0个0和0个1的时候最多组成0个字符串,所以在一开始全部赋为0即可
        // for(int i = 1; i <= strs.size(); ++i){
        //     int one = 0;
        //     int zero = 0;
        //     for(char c : strs[i-1]){
        //         if(c == '0') zero++;
        //         if(c == '1') one++;
        //     }
        //     //接下来就是考虑要不要取当前数字
        //     for(int j = 0; j <= m; ++j){
        //         for(int k = 0; k <= n; ++k){
        //             if(zero <= j && one <= k){
        //                 dp[i][j][k] = dp[i-1][j-zero][k-one]+1;
        //             }
        //             dp[i][j][k] = max(dp[i][j][k],dp[i-1][j][k]);
        //         }
        //     }
        // }
        // return dp[strs.size()][m][n];

        //只和前一维的结果有关系
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));
        //basecase就是对于取0个0和0个1我们只有0种方法
        //这次内部循环要反向遍历了,因为要取左上的,不能从前往后更新,这样会把左上的给更新掉
        for(int i = 0; i < strs.size(); ++i){
            int zero = 0;
            int one = 0;
            for(char c : strs[i]){
                if(c == '0') zero++;
                if(c == '1') one++;
            }
            for(int j = m; j >= zero; --j){
                for(int k = n; k >= one; --k){
                    dp[j][k] = max(dp[j][k],dp[j-zero][k-one]+1);
                }
            }
        }
        return dp[m][n];
    }
// private:
//     int res = 0;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值