一和零
问题
在计算机界中,我们总是追求用有限的资源获取最大的收益。
现在,假设你分别支配着 m 个 0 和 n 个 1。另外,还有一个仅包含 0 和 1 字符串的数组。
你的任务是使用给定的 m 个 0 和 n 个 1 ,找到能拼出存在于数组中的字符串的最大数量。每个 0 和 1 至多被使用一次。
注意:
- 给定 0 和 1 的数量都不会超过 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)
链接:https://leetcode-cn.com/problems/ones-and-zeroes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
1. 确定状态
设 f【a】【m】【n】,a表示字符串数组,m表示使用0的个数,n表示使用1的个数。
总体表示在a字符串数组的情况下,使用m个0和n个1可以拼出字符串的最大数量。
M表示新增的字符串需要0的个数。
N表示新增的字符串需要1的个数。
2. 转移方程
f【a】【m】【n】=
- 拼出新增的字符串,f【a-1】【m-M】【n-N】 + 1
- 不拼出, f【a-1】【m】【n】
f【a】【m】【n】 = Max(f【a-1】【m-M】【n-N】 + 1, f【a-1】【m】【n】)
3. 初始条件和边界情况
f【0】【m】【n】 = 0
m >= M, n >= N.
由于每个字符串只能使用一次(即有限背包),因此在更新f【m】【n】时, m和n都需要从大到小进行枚举
4. 计算顺序
从小到大
代码
因为不需要存储目前字符串组所以,采用二维数组表示整个状态
/**
* @param {string[]} strs
* @param {number} m
* @param {number} n
* @return {number}
*/
var findMaxForm = function (strs, m, n) {
var f = new Array(m + 1);
for (let i = 0; i < f.length; ++i) {
f[i] = new Array(n + 1);
f[i].fill(0);
}
console.dir(f);
for (let s of strs) {
// 计算strs中m,n的值
var M = 0;
var N = 0;
for (let char of s) {
if (char == 0) M++;
else N++;
}
for (var i = m; i >= M; i--) {
for (var j = n; j >= N; j--) {
f[i][j] = Math.max(f[i - M][j - N] + 1, f[i][j]);
}
}
}
return f[m][n];
};