题目

image.png

思路

  • 暴力递归:当字符串所要求的0和1小于等于当前剩余m和n,我们可以对该字符进行选用或不选用,大于时不选用该字符串,直接暴力这几种情况,选出最大可能性的。等价于背包问题
  • 备忘录:由于递归会超时,因为有许多重复分支,可以用容器记录下来
  • 动态规划:状态转移就是暴力递归中的可能性,dp数组要用三维表示,dp[插入/不插入第i个字符串][m个1][n个0] 组合最多的字符串数量
  • 优化动态规划的dp数组,通过画图很容易发现,对于二维来说,如果每次更新数组只依赖于前一维以及单独其他个别数据,这种是可以优化为一维数组,对于三维来说,如果每次更新数组依赖前二维数组,那么这个三维可以优化为二维

代码

  1. 1.暴力递归回溯超时
  2. public int findMaxForm(String[] strs, int m, int n) {
  3. Map<String, Integer> map = new HashMap<>();
  4. for (String s : strs) {
  5. int zero = 0, one = 0;
  6. for (int i = 0; i < s.length(); i++) {
  7. if ('0' == s.charAt(i)) zero++;
  8. if ('1' == s.charAt(i)) one++;
  9. }
  10. String key = zero + "-" + one;
  11. int count = map.getOrDefault(key, 0) + 1;
  12. map.put(key, count);
  13. }
  14. return recur(map, m, n);
  15. }
  16. public int recur(Map<String, Integer> map, int m, int n) {
  17. if (m == 0 && n == 0) return 0;
  18. int max = 0;
  19. for (int i = 0; i <= m; i++) {
  20. for (int j = 0; j <= n; j++) {
  21. String key = i + "-" + j;
  22. if (!map.containsKey(key) || map.get(key) <= 0) continue;
  23. int count = map.get(key);
  24. int k = count == 0 ? 0 : 1;
  25. if (count > 0) map.put(key, count - 1);
  26. max = Math.max(max, recur(map, m - i, n - j) + k);
  27. if (count > 0) map.put(key, count);
  28. }
  29. }
  30. return max;
  31. }
  32. //1. 暴力回溯超时
  33. public int findMaxForm(String[] strs, int m, int n) {
  34. boolean[] flag = new boolean[strs.length];
  35. return recur(strs, flag, m, n);
  36. }
  37. Map<String, Integer> map = new HashMap<>();
  38. public int recur(String[] strs, boolean[] flag, int m, int n) {
  39. if (m == 0 && n == 0) return 0;
  40. if (m < 0 || n < 0) return -1;
  41. int max = 0;
  42. for (int j = 0; j < strs.length; j++) {
  43. if (flag[j]) continue;
  44. int zero = 0, one = 0;
  45. for (int i = 0; i < strs[j].length(); i++) {
  46. if ('0' == strs[j].charAt(i)) zero++;
  47. else one++;
  48. }
  49. flag[j] = true;
  50. max = Math.max(max, recur(strs, flag, m - zero, n - one) + 1);
  51. flag[j] = false;
  52. }
  53. return max;
  54. }
  55. 1.暴力递归超时
  56. public int findMaxForm(String[] strs, int m, int n) {
  57. return recur(strs, 0, m, n);
  58. }
  59. public int recur(String[] strs, int index, int m, int n) {
  60. if (index >= strs.length) return 0;
  61. int zero = 0, one = 0;
  62. for (int i = 0; i < strs[index].length(); i++) {
  63. if ('0' == strs[index].charAt(i))
  64. zero++;
  65. else
  66. one++;
  67. }
  68. if (m - zero >= 0 && n - one >= 0)
  69. return Math.max(recur(strs, index + 1, m, n),
  70. recur(strs, index + 1, m - zero, n - one) + 1);
  71. else
  72. return recur(strs, index + 1, m, n);
  73. }
  74. 2.备忘录
  75. public int findMaxForm(String[] strs, int m, int n) {
  76. return recur(strs, 0, m, n);
  77. }
  78. Map<String ,Integer> map = new HashMap<>();
  79. public int recur(String[] strs, int index, int m, int n) {
  80. if (index >= strs.length) return 0;
  81. String key = index + "-" + m + "-" + n;
  82. if (map.containsKey(key)) return map.get(key);
  83. int zero = 0, one = 0, res = 0;
  84. for (int i = 0; i < strs[index].length(); i++) {
  85. if ('0' == strs[index].charAt(i))
  86. zero++;
  87. else
  88. one++;
  89. }
  90. if (m >= zero && n >= one)
  91. res = Math.max(
  92. recur(strs, index + 1, m, n),
  93. recur(strs, index + 1, m - zero, n - one) + 1);
  94. else
  95. res = recur(strs, index + 1, m, n);
  96. map.put(key, res);
  97. return res;
  98. }
  99. 3. 动态规划,三维dp数组可以看做是一个长方体
  100. public int findMaxForm(String[] strs, int m, int n) {
  101. //dp[插入/不插入第i个字符串][m个1][n个0] 组合最多的字符串数量
  102. int[][][] dp = new int[strs.length + 1][m + 1][n + 1];
  103. for (int k = 1; k <= strs.length; k++) {
  104. String s = strs[k - 1];
  105. int zero = 0, one = 0;
  106. for (int i = 0; i < s.length(); i++) {
  107. if ('0' == s.charAt(i))
  108. zero++;
  109. else
  110. one++;
  111. }
  112. for (int i = 0; i <= m; i++) {
  113. for (int j = 0; j <= n; j++) {
  114. if (i >= zero && j >= one)
  115. dp[k][i][j] = Math.max(dp[k - 1][i][j], dp[k - 1][i - zero][j - one] + 1);
  116. else
  117. dp[k][i][j] = dp[k - 1][i][j];
  118. }
  119. }
  120. }
  121. return dp[strs.length][m][n];
  122. }
  123. //4.优化dp数组,我们看到每次只是用到了上一层的长方形的面,因此可以转换为二维数组
  124. public int findMaxForm(String[] strs, int m, int n) {
  125. int[][] dp = new int[m + 1][n + 1];
  126. for (String s : strs) {
  127. int zero = 0, one = 0;
  128. for (int i = 0; i < s.length(); i++) {
  129. if ('0' == s.charAt(i)) zero++;
  130. else one++;
  131. }
  132. for (int i = m; i >= zero; i--) {
  133. for (int j = n ; j >= one; j--) {
  134. dp[i][j] = Math.max(dp[i - zero][j - one] + 1, dp[i][j]);
  135. }
  136. }
  137. }
  138. return dp[m][n];
  139. }

一和零