leetcode474. 一和零(动态规划-java)

265 篇文章 2 订阅
235 篇文章 0 订阅

leetcode474. 一和零

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/ones-and-zeroes

题目描述

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

解题思路

这个题还是背包问题,每次都是两个选择,选或者不选,只不过这题扩展的一点是。选择后重量是有两个维度,但解题框架是一样的,
process(不选)
process(选)
然后两种情况求最值。

解法一 递归加缓存

 /**
     * 一和零
     * @param strs
     * @param m
     * @param n
     * @return
     */
    public  int findMaxForm(String[] strs, int m, int n) {
        int L = strs.length;
        int[][][]dp = new int[m + 1][n + 1][L + 1];
        return process(strs,m,n,0,dp);
    }

    /**
     * 递归加缓存
     * @param strs
     * @param m
     * @param n
     * @param index
     * @param dp
     * @return
     */
    public int process(String[]strs,int m,int n,int index,int[][][]dp){
        //base case 就没法选了,返回0
        if (index >= strs.length){
            return 0;
        }
        //超过 越界 返回0
        if (m < 0 || n < 0){
            return 0;
        }
        //从缓存中拿
        if(dp[m][n][index] != 0){
            return dp[m][n][index];
        }
        //0的数量
        int zeroNum = getZeroNum(strs[index]);
        //1的数量
        int oneNum = strs[index].length() - zeroNum;
        //不选的时候
        int p1 = process(strs,m,n,index + 1,dp);
        int p2 = 0;
        //选择的时候
        if(m - zeroNum >= 0&& n - oneNum >= 0){
            p2 = 1 + process(strs,m - zeroNum,n - oneNum,index + 1,dp);
        }
        dp[m][n][index] = Math.max(p1,p2);
        return Math.max(p1,p2);
    }

    /**
     * 计算0的数量
     * @param str
     * @return
     */
    public  int getZeroNum(String str){
        if (str.length() == 0){
            return 0;
        }
        int i = 0;
        for (char c : str.toCharArray()){
            if(c == '0'){
                i++;
            }
        }
        return i;
    }

动态规划

碰到每个字符串时,只有选择和不选两种情况,我们要选两种情况里的最大值,可以推出下面的状态转移方程:
dp[i][j] = Math.max(dp[i][j],dp[i - zeroNum][j - one] + 1);
根据方程,可以直接写代码了。

代码演示

 /**
     *
     * @param strs
     * @param m 个 0
     * @param n 个 1
     * @return
     */
    public  int findMaxForm1(String[] strs, int m, int n) {
        int[][] dp = new int[m + 1][n + 1];
        for (String str : strs){
            int zeroNum = getZeroNum(str);
            int one = str.length() - zeroNum;
            for (int i = m ; i >= zeroNum;i--){
                for (int j = n; j >= one;j--){
                    dp[i][j] = Math.max(dp[i][j],dp[i - zeroNum][j - one] + 1);
                }
            }
        }
        return dp[m][n];
    }

动态规划专题

leetcode64. 最小路径和

leetcode416. 分割等和子集

leetcode354. 俄罗斯套娃信封问题

leetcode300. 最长递增子序列

leetcode329. 矩阵中的最长递增路径

leetcode494. 目标和

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值