474. Ones and Zeroes [Medium]

自己不会做,看的discuss

遍历输入的String数组,对于每个str,先计数0存为zeroes、1存为ones

从dp[zeroes][ones]到dp[m][n]范围内的每一个dp单元对应的字符串集都有可能加入当前str,用双层循环遍历更新该范围内的dp单元

注意必须从右下角往dp[zeroes][ones]遍历

因为如果从dp[zeroes][ones]开始,若元素被更新,说明对应的字符串集加入了str,其右下方的dp单元更新若用到这样的单元,就会发生str重复

从右下角开始,每一个对应的字符串集加入了str的dp单元之后不会也被用于其左上方的dp单元更新,就避免了重复

/**
 * 自己不会做,看的discuss
 * 0-1背包问题动态规划 + 空间优化,二维dp数组
 */
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m + 1][n + 1];
        for (String str : strs) {
            int zeroes = 0, ones = 0;
            for (int i = 0; i < str.length(); i++) // 计算str中0的个数
                if (str.charAt(i) == '0')
                    zeroes++;
            ones = str.length() - zeroes; // 计算str中1的个数
            for (int i = m; i >= zeroes; i--) // 此处的一定要从m和n往小循环,如果从小往大会重复使用当前str
                for (int j = n; j >= ones; j--)
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeroes][j - ones] + 1);
        }
        return dp[m][n];
    }
}
/** 
 * 和上面一段代码一样的做法,0-1背包问题动态规划 + 空间优化,二维dp数组
 * 这里字符串0或1的计数用了比较新的filter()方法,count()返回long类型所以要显示转换为int
 * 但是运行时间比遍历计数久
 */
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m + 1][n + 1];
        for (String str : strs) {
            int zeroes = (int)str.chars().filter(x -> x == '0').count(); // 计算str中0的个数
            int ones = str.length() - zeroes;
            for (int i = m; i >= zeroes; i--)
                for (int j = n; j >= ones; j--)
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeroes][j - ones] + 1);
        }
        return dp[m][n];
    }
}
/**
 * 传统0-1背包问题动态规划的解法,三维dp数组
 */
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int nums = strs.length;
        int[][][] dp = new int[nums + 1][m + 1][n + 1];
        for (int k = 1; k <= nums; k++) {
            int zeroes = (int)strs[k - 1].chars().filter(x -> x == '0').count();
            int ones = strs[k - 1].length() - zeroes;
            for (int i = 0; i <= m; i++)
                for (int j = 0; j <= n; j++) {
                    dp[k][i][j] = dp[k - 1][i][j]; // 先继承k-1的结果
                    if (i >= zeroes && j >= ones) // 再更新符合条件的dp位置
                        dp[k][i][j] = Math.max(dp[k][i][j], dp[k - 1][i - zeroes][j - ones] + 1);
                }
        }
        return dp[nums][m][n];
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值