LeetCode 474. Ones and Zeroes(动态规划)

题目

大意:给出一个全为01串的字符串数组,每个串都会消耗一定数量的0和1,分别给出0和1的总个数,要求在消耗完给出的01资源之前找出最多的字符串。

Example 1:
    Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3
    Output: 4
    Explanation: This are totally 4 strings can be formed by the using 
                 of 5 0s and 3 1s, which are “10,”0001”,”1”,”0”

Example 2:
    Input: Array = {"10", "0", "1"}, m = 1, n = 1
    Output: 2
    Explanation: You could form "10", but then you'd have nothing 
                 left. Better form "0" and "1".

思路

把模型转换一下,就发现这是一个01背包问题。

了解背包问题
将该题类比为01背包

物品:每个字符串
物品的重量:该字符串消耗的0和1的数量
物品的价值:1,用于计数,要求最大总价值即选出字符串的数量最多
背包总容量:[m][n],m为给定 0 的个数,n为给定 1 的个数
特点:每个物品(字符串)只能取一次,因此是01背包;而且不要求恰好用完01的资源,即背包不需要恰好装满,可以不装满。

定义状态

dp[i][zero][one]:在背包容量为[zero][one]时,从前i个字符串选出若干串放进背包,所获得的最大字符串数量。
因为背包不要求恰好装满(0和1不一定要恰好消耗完),所以初始值全为0。

状态转换

字符串str消耗的0和1为:n0, n1

若n0 > zero 或者 n1 > one,则str不可能放进当前背包
dp[i + 1][zero][one] = dp[i][zero][one]

否则,str有机会放进当前背包,需要与不放进该背包的情况比较,取最大值
dp[i + 1][zero][one] = max(1 + dp[i][zero - n0][one - n1], dp[i][zero][one] )

最终答案为
dp[size of strings][m][n]

优化空间

可以把三维降为二维,因为新的二维数组的数值都依赖于前一个二维数组,注意二维数组中的元素从大往小更新。
dp[zero][one] = max(1 + dp[zero - n0][one - n1], dp[zero][one])

最终答案为
dp[m][n]

代码

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        int size = strs.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));//二维数组代替三维,节省空间

        for (int i = 0; i < size; i++) {
            //计算每个字符串消耗的0和1
            int n0 = 0, n1 = 0;
            for (int j = 0; j < strs[i].length(); j++) if (strs[i][j] == '0') n0++;
            n1 = strs[i].length() - n0;

            //从大往小计算,避免右边找不到其所依赖的上一轮左边的值,若从左到右会过早覆盖旧值
            for (int zero = m; zero >= n0; zero--) {
                for (int one = n; one >= n1; one--) {
                    dp[zero][one] = max(dp[zero][one], 1 + dp[zero - n0][one - n1]);
                }
            }
        }

        return dp[m][n];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值