因此我们可以直接套用 01 背包的「状态定义」来做:
[
k
]
[
i
]
[
j
]
[k][i][j]
[k][i][j] 代表考虑前 k 件物品,在数字 1 容量不超过
i
i
i,数字 0 容量不超过
j
j
j 的条件下的「最大价值」(每个字符串的价值均为 1)
则可以得出状态转移方程
f
[
k
]
[
i
]
[
j
]
=
m
a
x
(
f
[
k
−
1
]
[
i
]
[
j
]
,
f
[
k
−
1
]
[
i
−
c
n
t
[
k
]
[
0
]
]
[
j
−
c
n
t
[
k
]
[
1
]
]
+
1
)
f[k][i][j]=max(f[k−1][i][j],f[k−1] [i−cnt[k][0]] [j−cnt[k][1]]+1)
f[k][i][j]=max(f[k−1][i][j],f[k−1][i−cnt[k][0]][j−cnt[k][1]]+1)
cnt则为记录0,1 元素出现的次数的数组。
代码如下:
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] zeroAndOne = new int[strs.length][2];
//记录strs每一个元素中0和1出现的次数
for (int i = 0; i < strs.length; i++) {
int zeroCnt = 0, oneCnt = 0;
for (int j = 0; j < strs[i].length(); j++) {
if (strs[i].charAt(j) == '1') {
oneCnt++;
} else {
zeroCnt++;
}
}
zeroAndOne[i][0] = zeroCnt;
zeroAndOne[i][1] = oneCnt;
}
//f数组为动态规划数组
int[][] f = new int[m + 1][n + 1];
//滚动数组
for (int k = 0; k < strs.length; k++) {
int zero = zeroAndOne[k][0], one = zeroAndOne[k][1];
//i>=zero,j>=one 确保数组不会越界
for (int i = m; i >= zero; i--) {
for (int j = n; j >= one; j--) {
//状态转移方程,这里去掉了物品维度
f[i][j] = Math.max(f[i][j], f[i - zero][j - one] + 1);
}
}
}
//返回最终结果
return f[m][n];
}
}