From 3c9a1bca9eb1916a04d0fbd3af772edee7d2c082 Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Tue, 4 Oct 2022 23:12:58 +0800 Subject: [PATCH] modify code --- .../class03/Code06_ClosestSubsequenceSum.java | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/大厂刷题班/class03/Code06_ClosestSubsequenceSum.java b/大厂刷题班/class03/Code06_ClosestSubsequenceSum.java index 1cb2c0b..e6131a1 100644 --- a/大厂刷题班/class03/Code06_ClosestSubsequenceSum.java +++ b/大厂刷题班/class03/Code06_ClosestSubsequenceSum.java @@ -11,17 +11,40 @@ import java.util.Arrays; // 而值很大,用动态规划的话,表会爆 public class Code06_ClosestSubsequenceSum { + // 数组左半部分的所有可能累加和都放在这里 public static int[] l = new int[1 << 20]; + + // 数组右半部分的所有可能累加和都放在这里 public static int[] r = new int[1 << 20]; public static int minAbsDifference(int[] nums, int goal) { if (nums == null || nums.length == 0) { return goal; } + // 收集数组左半部分,所有可能的累加和 + // 并且返回一共收集了几个数,就是le int le = process(nums, 0, nums.length >> 1, 0, 0, l); + // 收集数组右半部分,所有可能的累加和 + // 并且返回一共收集了几个数,就是re int re = process(nums, nums.length >> 1, nums.length, 0, 0, r); + // 把左半部分收集到的累加和排序 Arrays.sort(l, 0, le); + // 把左半部分收集到的累加和排序 Arrays.sort(r, 0, re--); + // 为什么要排序? + // 因为排序之后定位数字可以不回退 + // 比如你想累加和尽量接近10 + // 左半部分累加和假设为 : 0, 2, 3, 7, 9 + // 右半部分累加和假设为 : 0, 6, 7, 8, 9 + // 左部分累加和是0时,右半部分选哪个累加和最接近10,是9 + // 左部分累加和是2时,右半部分选哪个累加和最接近10,是8 + // 左部分累加和是3时,右半部分选哪个累加和最接近10,是7 + // 左部分累加和是7时,右半部分选哪个累加和最接近10,是0 + // 左部分累加和是9时,右半部分选哪个累加和最接近10,是0 + // 上面你可以看到, + // 当你从左往右选择左部分累加和时,右部分累加和的选取,可以从右往左 + // 这就非常的方便 + // 下面的代码就是这个意思 int ans = Math.abs(goal); for (int i = 0; i < le; i++) { int rest = goal - l[i]; @@ -33,13 +56,32 @@ public class Code06_ClosestSubsequenceSum { return ans; } + // 解释一下 + // nums[0..index-1]已经选了一些数字,组成了累加和sum + // 当前来到nums[index....end)这个范围,所有可能的累加和 + // 填写到arr里去 + // fill参数的意思是: 如果出现新的累加和,填写到arr的什么位置 + // 返回所有生成的累加和,现在填到了arr的什么位置 public static int process(int[] nums, int index, int end, int sum, int fill, int[] arr) { - if (index == end) { + if (index == end) { // 到了终止为止了,该结束了 + // 把当前的累加和sum + // 填写到arr[fill]的位置 + // 然后fill++,表示如果后续再填的话 + // 该放在什么位置了 arr[fill++] = sum; } else { + // 可能性1 : 不要当前的数字 + // 走一个分支,形成多少累加和,都填写到arr里去 + // 同时返回这个分支把arr填到了什么位置 fill = process(nums, index + 1, end, sum, fill, arr); + // 可能性2 : 要当前的数字 + // 走一个分支,形成多少累加和,都填写到arr里去 + // 接着可能性1所填到的位置,继续填写到arr里去 + // 这就是为什么要拿到上一个分支填到哪了 + // 因为如果没有这个信息,可能性2的分支不知道往哪填生成的累加和 fill = process(nums, index + 1, end, sum + nums[index], fill, arr); } + // 可能性1 + 可能性2,总共填了多少都返回 return fill; }