动态规划 - 474.⼀和零

89 阅读1分钟

4月日新计划更文活动 第13天

前言

动态规划专题,从简到难通关动态规划。

每日一题

今天的题目是 474. 一和零,难度为中等

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

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0' 和 '1' 组成
  • 1 <= m, n <= 100

题解

01背包

本题可以使用 0-1 背包的思想进行求解,将每一个字符串看作是一个物品,0 和 1 的数量就是物品的价值,需要在 m 个 0 和 n 个 1 的空间限制下获取最多的价值。我们用动态规划五部曲来解决一下这道题。

  1. 定义 dp 数组以及下标的含义

本题中,由于需要限制 0 和 1 的个数,因此可以将 dp 数组定义为一个二维数组,即 dp[i][j] 表示最多使用 i 个 0 和 j 个 1 最多可以表示多少个字符串。 例如,dp[1][1] 表示最多使用 1 个 0 和 1 个 1 能够表示多少个字符串。

  1. 确定递推公式

其次,我们需要确定递推公式。由于是一个 0-1 背包问题,因此我们使用动态规划来处理。对于 dp[i][j],表示使用前 i 个字符串能够组成的最大字符串集合,则根据题意,有如下递推公式:

dp[i][j] = Math.max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1)

其中 zeroCount 是当前字符串中 0 的个数,oneCount 是当前字符串中 1 的个数。即,我们要求解在使用前 i 个字符串时,限制 0 和 1 的数量下能够得到的最多字符串集合数。对于每一个字符串,如果它的 0 和 1 的数量都不超过限制 m 和 n,那么我们可以选择该字符串,且该选择带来的最大收益为 1,因此最终的结果就是能够获得的最大收益数。

  1. 如何初始化 dp 数组

由于根据递推公式,dp[0][0] 需要赋值为 0,因此我们可以初始化为一个全为 0 的二维数组。

  1. 如何确定遍历顺序

在对每一个字符串进行背包更新时,需要注意要倒序遍历(从大到小遍历),这是由于前面的更新值会被后面的值更新,因此要从大到小遍历以便于进行正确的更新。

  1. 举例推导 dp 数组
dp0123
00000
10111
20122
30123

根据上面的递推公式,我们可以写出函数:

function findMaxForm(strs: string[], m: number, n: number): number {
    const dp = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0));

    for (const str of strs) {
        let zeroCount = 0, oneCount = 0;
        for (const c of str) {
            if (c === '0') {
                zeroCount++;
            } else {
                oneCount++;
            }
        }
        for (let i = m; i >= zeroCount; i--) {
            for (let j = n; j >= oneCount; j--) {
                dp[i][j] = Math.max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1);
            }
        }
    }

    return dp[m][n];
};

image.png