内容来自刘宇波老师玩转算法面试
1、01 背包问题

| public class Solution { |
| |
| private static class Node { |
| |
| public int index; |
| public boolean b; |
| public int w; |
| public int v; |
| |
| public Node left; |
| public Node right; |
| |
| public Node() { |
| } |
| |
| public Node(int index, boolean b, int w, int v) { |
| this.index = index; |
| this.b = b; |
| this.w = w; |
| this.v = v; |
| } |
| } |
| |
| private static Node root; |
| |
| |
| |
| |
| public static int knapsack01(int[] w, int[] v, int C) { |
| if (w == null || w.length == 0 || v == null || v.length == 0) return 0; |
| if (w.length != v.length) return 0; |
| root = new Node(); |
| |
| Queue<Node> queue = new LinkedList<>(); |
| queue.add(root); |
| for (int i = 0; i < w.length; i++) { |
| List<Node> level = new ArrayList<>(); |
| int size = queue.size(); |
| for (int j = 0; j < size; j++) level.add(queue.remove()); |
| |
| for (Node node : level) { |
| node.left = new Node(i, true, node.w + w[i], node.v + v[i]); |
| node.right = new Node(i, false, node.w, node.v); |
| queue.add(node.left); |
| queue.add(node.right); |
| } |
| } |
| |
| List<Node> allNode = new ArrayList<>(); |
| perOrder(root, allNode); |
| |
| int res = -1; |
| for (Node node : allNode) { |
| if (node.w <= C) res = Math.max(res, node.v); |
| } |
| |
| return res; |
| } |
| |
| private static void perOrder(Node node, List<Node> list) { |
| if (node == null) return; |
| |
| list.add(node); |
| perOrder(node.left, list); |
| perOrder(node.right, list); |
| } |
| } |
2、贪心算法

3、递归
3.1、图示

3.2、实现
| |
| |
| |
| public static int knapsack01(int[] w, int[] v, int C) { |
| if (w == null || w.length == 0 || v == null || v.length == 0) return 0; |
| if (w.length != v.length) return 0; |
| |
| return dp(w, v, w.length - 1, C); |
| } |
| |
| |
| |
| |
| private static int dp(int[] w, int[] v, int index, int c) { |
| if (index < 0 || c <= 0) return 0; |
| |
| |
| int res = dp(w, v, index - 1, c); |
| if (c >= w[index]) { |
| res = Math.max(res, v[index] + dp(w, v, index - 1, c - w[index])); |
| } |
| |
| return res; |
| } |
4、记忆化搜索
| public class Solution { |
| |
| private static int[][] memo; |
| |
| |
| |
| |
| public static int knapsack01(int[] w, int[] v, int C) { |
| if (w == null || w.length == 0 || v == null || v.length == 0) return 0; |
| if (w.length != v.length) return 0; |
| |
| memo = new int[w.length][C + 1]; |
| for (int[] arr : memo) Arrays.fill(arr, -1); |
| return dp(w, v, w.length - 1, C); |
| } |
| |
| |
| |
| |
| private static int dp(int[] w, int[] v, int index, int c) { |
| if (index < 0 || c <= 0) return 0; |
| |
| if (memo[index][c] != -1) return memo[index][c]; |
| |
| |
| int res = dp(w, v, index - 1, c); |
| if (c >= w[index]) { |
| res = Math.max(res, v[index] + dp(w, v, index - 1, c - w[index])); |
| } |
| memo[index][c] = res; |
| |
| return res; |
| } |
| } |
5、动态规划
5.1、图示


5.2、实现
| public class Solution { |
| |
| |
| |
| |
| public static int knapsack01(int[] w, int[] v, int C) { |
| if (w == null || w.length == 0 || v == null || v.length == 0) return 0; |
| if (w.length != v.length) return 0; |
| |
| |
| int[][] memo = new int[w.length][C + 1]; |
| for (int[] arr : memo) Arrays.fill(arr, -1); |
| |
| for (int c = 0; c <= C; c++) { |
| |
| memo[0][c] = (c >= w[0] ? v[0] : 0); |
| } |
| |
| for (int i = 1; i < memo.length; i++) { |
| for (int c = 0; c <= C; c++) { |
| |
| |
| int res = memo[i - 1][c]; |
| if (c >= w[i]) { |
| res = Math.max(res, v[i] + memo[i - 1][c - w[i]]); |
| } |
| memo[i][c] = res; |
| } |
| } |
| |
| return memo[w.length - 1][C]; |
| } |
| } |
6、01 背包问题的优化
6.1、空间优化 1

| public class Solution { |
| |
| |
| |
| |
| public static int knapsack01(int[] w, int[] v, int C) { |
| if (w == null || w.length == 0 || v == null || v.length == 0) return 0; |
| if (w.length != v.length) return 0; |
| |
| |
| int[][] memo = new int[2][C + 1]; |
| for (int[] arr : memo) Arrays.fill(arr, -1); |
| |
| for (int c = 0; c <= C; c++) { |
| |
| memo[0][c] = (c >= w[0] ? v[0] : 0); |
| } |
| |
| for (int i = 1; i <= w.length - 1; i++) { |
| for (int c = 0; c <= C; c++) { |
| |
| |
| int res = memo[(i - 1) % 2][c]; |
| if (c >= w[i]) { |
| res = Math.max(res, v[i] + memo[(i - 1) % 2][c - w[i]]); |
| } |
| memo[i % 2][c] = res; |
| } |
| } |
| |
| return memo[(w.length - 1) % 2][C]; |
| } |
| } |
6.2、空间优化 2


| public class Solution { |
| |
| |
| |
| |
| public static int knapsack01(int[] w, int[] v, int C) { |
| if (w == null || w.length == 0 || v == null || v.length == 0) return 0; |
| if (w.length != v.length) return 0; |
| |
| |
| int[] memo = new int[C + 1]; |
| Arrays.fill(memo, -1); |
| |
| for (int c = 0; c <= C; c++) { |
| |
| memo[c] = (c >= w[0] ? v[0] : 0); |
| } |
| |
| for (int i = 1; i <= w.length - 1; i++) { |
| for (int c = C; c >= w[i]; c--) { |
| |
| |
| memo[c] = Math.max(memo[c], v[i] + memo[c - w[i]]); |
| if (i == w.length - 1 && c == C) return memo[c]; |
| } |
| } |
| |
| return memo[C]; |
| } |
| } |
7、01 背包问题的变种

8、面试中的 01 背包问题
416 - 分割等和子集
更多问题
322 - 零钱兑换
377 - 组合总和 Ⅳ
474 - 一和零
139 - 单词拆分
494 - 目标和
9.1、图示


9.2、递归
| public static boolean canPartition(int[] nums) { |
| int sum = 0; |
| for (int num : nums) sum += num; |
| if (sum % 2 != 0) return false; |
| int c = sum / 2; |
| |
| return dp(nums, nums.length - 1, c); |
| } |
| |
| |
| |
| |
| private static boolean dp(int[] nums, int index, int c) { |
| if(c == 0) return true; |
| if (index < 0 || c < 0) return false; |
| |
| |
| boolean res = false; |
| res = res || dp(nums, index - 1, c); |
| res = res || dp(nums, index - 1, c - nums[index]); |
| |
| return res; |
| } |
9.3、记忆化搜索
| public class CanPartition2 { |
| |
| private static int[][] memo; |
| |
| public static boolean canPartition(int[] nums) { |
| int sum = 0; |
| for (int num : nums) sum += num; |
| if (sum % 2 != 0) return false; |
| int c = sum / 2; |
| |
| |
| memo = new int[nums.length][c + 1]; |
| for (int[] arr : memo) Arrays.fill(arr, -1); |
| return dp(nums, nums.length - 1, c); |
| } |
| |
| |
| |
| |
| private static boolean dp(int[] nums, int index, int c) { |
| if (c == 0) return true; |
| if (index < 0 || c < 0) return false; |
| |
| if (memo[index][c] != -1) return memo[index][c] == 1; |
| |
| |
| boolean res = false; |
| res = res || dp(nums, index - 1, c); |
| res = res || dp(nums, index - 1, c - nums[index]); |
| memo[index][c] = res ? 1 : 0; |
| |
| return res; |
| } |
| } |
9.4、动态规划
| public static boolean canPartition(int[] nums) { |
| int sum = 0; |
| for (int num : nums) sum += num; |
| if (sum % 2 != 0) return false; |
| int C = sum / 2; |
| |
| |
| boolean[] memo = new boolean[C + 1]; |
| |
| for (int c = 0; c <= C; c++) { |
| |
| memo[c] = nums[0] == c; |
| } |
| |
| for (int i = 1; i <= nums.length - 1; i++) { |
| for (int c = C; c >= nums[i]; c--) { |
| memo[c] = memo[c] || memo[c - nums[i]]; |
| if (i == nums.length - 1 && c == C) return memo[c]; |
| } |
| } |
| |
| return memo[C]; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步