自己不会做,看的discuss
遍历输入的String数组,对于每个str,先计数0存为zeroes、1存为ones
从dp[zeroes][ones]到dp[m][n]范围内的每一个dp单元对应的字符串集都有可能加入当前str,用双层循环遍历更新该范围内的dp单元
注意必须从右下角往dp[zeroes][ones]遍历:
因为如果从dp[zeroes][ones]开始,若元素被更新,说明对应的字符串集加入了str,其右下方的dp单元更新若用到这样的单元,就会发生str重复
从右下角开始,每一个对应的字符串集加入了str的dp单元之后不会也被用于其左上方的dp单元更新,就避免了重复
/**
* 自己不会做,看的discuss
* 0-1背包问题动态规划 + 空间优化,二维dp数组
*/
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for (String str : strs) {
int zeroes = 0, ones = 0;
for (int i = 0; i < str.length(); i++) // 计算str中0的个数
if (str.charAt(i) == '0')
zeroes++;
ones = str.length() - zeroes; // 计算str中1的个数
for (int i = m; i >= zeroes; i--) // 此处的一定要从m和n往小循环,如果从小往大会重复使用当前str
for (int j = n; j >= ones; j--)
dp[i][j] = Math.max(dp[i][j], dp[i - zeroes][j - ones] + 1);
}
return dp[m][n];
}
}
/**
* 和上面一段代码一样的做法,0-1背包问题动态规划 + 空间优化,二维dp数组
* 这里字符串0或1的计数用了比较新的filter()方法,count()返回long类型所以要显示转换为int
* 但是运行时间比遍历计数久
*/
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for (String str : strs) {
int zeroes = (int)str.chars().filter(x -> x == '0').count(); // 计算str中0的个数
int ones = str.length() - zeroes;
for (int i = m; i >= zeroes; i--)
for (int j = n; j >= ones; j--)
dp[i][j] = Math.max(dp[i][j], dp[i - zeroes][j - ones] + 1);
}
return dp[m][n];
}
}
/**
* 传统0-1背包问题动态规划的解法,三维dp数组
*/
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int nums = strs.length;
int[][][] dp = new int[nums + 1][m + 1][n + 1];
for (int k = 1; k <= nums; k++) {
int zeroes = (int)strs[k - 1].chars().filter(x -> x == '0').count();
int ones = strs[k - 1].length() - zeroes;
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++) {
dp[k][i][j] = dp[k - 1][i][j]; // 先继承k-1的结果
if (i >= zeroes && j >= ones) // 再更新符合条件的dp位置
dp[k][i][j] = Math.max(dp[k][i][j], dp[k - 1][i - zeroes][j - ones] + 1);
}
}
return dp[nums][m][n];
}
}