题目: 一和零

  • 在计算机界中,我们总是追求用有限的资源获取最大的收益。
  • 现在,假设你分别支配着 m 个0和 n 个 1。另外,还有一个仅包含 0 和 1 字符串的数组。
  • 你的任务是使用给定的m0n1,找到能拼出存在于数组中的字符串的最大数量。每个01至多被使用一次。
注意:
  • 给定01的数量都不会超过100。
  • 给定字符串数组的长度不会超过600。
示例 1:
输入: Array = {"10", "0001", "111001", "1", "0"},m = 5, n = 3
输出: 4
解释: 总共 4 个字符串可以通过 5 个 0 和 3 个 1 拼出,即 "10","0001","1","0" 。
示例 2:
输入: Array = {"10", "0", "1"}, m = 1, n = 1
输出: 2
解释: 你可以拼出 "10",但之后就没有剩余数字了。更好的选择是拼出 "0" 和 "1" 。

来源:力扣(LeetCode)第474题

链接:https://leetcode-cn.com/problems/ones-and-zeroes

分析:

  • 典型的背包问题,有两个状态,i是当0有i个时,j是当1有j个时。
  • 我们举出小于m和小于n的0和1的个数。每当一个str进来时有两种选择,一种是放进去,另一种不放。
  • 如果放进去,那么放完后还要加上i-count(0)j-count(1)时候的个数,如果不放就不用动它。比较两者谁大,把大的存在当前状态。
  • 我们每次把所有状态都更新一遍。

代码:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        for (String str : strs) {
            int zero = 0, one = 0;
            // 找到0 和 1的个数
            for (int i = 0; i < str.length(); i++) {
                if (str.charAt(i) == '1') one++;
                else zero++;
            }
            // 如果str的0和1的个数是x,y,那么我们将能够装下x个0,和y个1的状态依次进行比较。
            // 如果装下x个0, y个1后,然后查看剩下的i-x个0和j-y个1能装下几个,这个状态在上一次已经算过了。
            for (int i = m; i >= zero; i--) 
                for (int j = n; j >= one; j--) 
                    dp[i][j] = Math.max(dp[i][j], dp[i-zero][j-one] + 1);
        }
        return dp[m][n];
    }
}