2021-04-04一和零

给你一个二进制字符串数组 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 。

解:动态规划

本题与动态规划方法的01背包模型相似,但背包模型中容量仅用一个变量表示,而本题中,容量则包括0和1的容量两个变量,因此通过一个三维的dp数组来解决。
用dp [ l ] [ i ] [ j ]表示strs中,前 l 个字符串满足1最多 i 个,0最多 j 个的最大子集数。(即前 l 个的最佳组合),则

  1. 若当前字符串strs[ l ]未被选择,则:dp[ l ] [ i ] [ j ] = dp[ l -1 ] [ i ] [ j ]
  2. 若选择当前字符串strs[ l ]被选择,则:dp[ l ] [ i ] [ j ] = dp[ l -1 ] [ i-l.oneNum ] [ j-l.ZeroNum ]+1
    (其中若满足选择当前字符串,i、j的值必须满足 i >= l.oneNum、j >= l.zeroNum;否则dp[ i ][ j ]的值按照第一条获取。)

最后dp [ n ] [ m ]即结果

示例:
strs:0001 , 0101 , 1000 , 1000;m = 9 , n = 3;

  1. 初始化dp数组全部为0
  2. 遍历strs,求每个str[l]对应的dp二维数组:
    l = 0:
    在这里插入图片描述
    l = 1:
    在这里插入图片描述
    l = 2:
    在这里插入图片描述
    l = 3:
    在这里插入图片描述
    空间优化:
    由于每次求 l+1的dp二维数组时,都是根据 l 的数组进行取值,最后结果也用不上前面的数组,因此只设置滚动数组,取两个数组,一个作为取值的根据,一个用来赋新值。

时间优化:
根据前面分析,当 i < n 和 j < m 时,dp[ l ][ i ] [ j ] = dp[ l-1 ] [ i ] [ j ],因此求 l 的二维数组时,可以直接从i = n;j = m往后更新,不用更新全部数组。
3. 返回dp[ n ][ m ]。

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        int zeroNum = 0;
        int oneNum = 0;
        int i,j;
        vector<vector<int>> dpTemp(n+1,vector<int>(m+1,0));
        vector<vector<int>> dp(n+1,vector<int>(m+1,0));

        for(int l=0 ; l<strs.size() ; l++)
        {
            zeroNum = count(strs[l].begin() , strs[l].end() , '0');
            oneNum = count(strs[l].begin() , strs[l].end() , '1');
            for(i = oneNum ; i<n+1 ; i++)
            {
                for(j=zeroNum ; j<m+1 ; j++)
                {
                    dp[i][j] = max(dpTemp[i][j],dpTemp[i-oneNum][j-zeroNum]+1);
                }
            }
            dpTemp = dp;
        }
        return dp[n][m];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值