From 5817dce9cf21e3d7370f938172cb513a22002c26 Mon Sep 17 00:00:00 2001 From: algorithmzuo <64469262+algorithmzuo@users.noreply.github.com> Date: Sat, 16 May 2020 16:54:16 +0800 Subject: [PATCH] update on 2020-05-16 --- .../Code04_SerializeAndReconstructTree.java | 1 + src/class11/Code02_PrintAllSubsquences.java | 8 ++- src/class11/Code03_PrintAllPermutations.java | 22 ++++++-- src/class11/Code06_ConvertToLetterString.java | 3 ++ src/class11/Code07_Knapsack.java | 19 ++++--- src/class11/Code08_CardsInLine.java | 31 +++++++---- src/class11/Code09_NQueens.java | 21 +++++--- src/class12/Code01_RobotWalk.java | 52 +++++++++++++++++++ src/class12/Code03_Knapsack.java | 11 ++-- 9 files changed, 136 insertions(+), 32 deletions(-) diff --git a/src/class07/Code04_SerializeAndReconstructTree.java b/src/class07/Code04_SerializeAndReconstructTree.java index a502f13..fecd6ac 100644 --- a/src/class07/Code04_SerializeAndReconstructTree.java +++ b/src/class07/Code04_SerializeAndReconstructTree.java @@ -101,6 +101,7 @@ public class Code04_SerializeAndReconstructTree { if (poslist == null || poslist.size() == 0) { return null; } + // 左右中 -> stack(中右左) Stack stack = new Stack<>(); while (!poslist.isEmpty()) { stack.push(poslist.poll()); diff --git a/src/class11/Code02_PrintAllSubsquences.java b/src/class11/Code02_PrintAllSubsquences.java index fd5e896..28509c3 100644 --- a/src/class11/Code02_PrintAllSubsquences.java +++ b/src/class11/Code02_PrintAllSubsquences.java @@ -14,6 +14,10 @@ public class Code02_PrintAllSubsquences { return ans; } + // str固定,不变 + // index此时来到的位置, 要 or 不要 + // 如果index来到了str中的终止位置,把沿途路径所形成的答案,放入ans中 + // 之前做出的选择,就是path public static void process1(char[] str, int index, List ans, String path) { if (index == str.length) { ans.add(path); @@ -37,7 +41,9 @@ public class Code02_PrintAllSubsquences { return ans; } - public static void process2(char[] str, int index, HashSet set, String path) { + // str index set + public static void process2(char[] str, int index, + HashSet set, String path) { if (index == str.length) { set.add(path); return; diff --git a/src/class11/Code03_PrintAllPermutations.java b/src/class11/Code03_PrintAllPermutations.java index 7a8a589..349eedd 100644 --- a/src/class11/Code03_PrintAllPermutations.java +++ b/src/class11/Code03_PrintAllPermutations.java @@ -15,16 +15,21 @@ public class Code03_PrintAllPermutations { return res; } - public static void process(char[] str, int i, ArrayList res) { + // str[0..i-1]已经做好决定的 + // str[i...]都有机会来到i位置 + // i终止位置,str当前的样子,就是一种结果 -> ans + public static void process(char[] str, int i, ArrayList ans) { if (i == str.length) { - res.add(String.valueOf(str)); + ans.add(String.valueOf(str)); } - for (int j = i; j < str.length; j++) { + // 如果i没有终止,i... 都可以来到i位置 + for (int j = i; j < str.length; j++) { // j i后面所有的字符都有机会 swap(str, i, j); - process(str, i + 1, res); + process(str, i + 1, ans); swap(str, i, j); } } + public static ArrayList permutationNoRepeat(String str) { ArrayList res = new ArrayList<>(); @@ -36,17 +41,26 @@ public class Code03_PrintAllPermutations { return res; } + // str[0..i-1]已经做好决定的 + // str[i...]都有机会来到i位置 + // i终止位置,str当前的样子,就是一种结果 -> ans public static void process2(char[] str, int i, ArrayList res) { if (i == str.length) { res.add(String.valueOf(str)); + return; } boolean[] visit = new boolean[26]; // visit[0 1 .. 25] for (int j = i; j < str.length; j++) { + // str[j] = 'a' -> 0 visit[0] -> 'a' + + // str[j] = 'z' -> 25 visit[25] -> 'z' if (!visit[str[j] - 'a']) { + visit[str[j] - 'a'] = true; swap(str, i, j); process2(str, i + 1, res); swap(str, i, j); + } } } diff --git a/src/class11/Code06_ConvertToLetterString.java b/src/class11/Code06_ConvertToLetterString.java index 1a21ffa..5a91022 100644 --- a/src/class11/Code06_ConvertToLetterString.java +++ b/src/class11/Code06_ConvertToLetterString.java @@ -9,6 +9,7 @@ public class Code06_ConvertToLetterString { return process(str.toCharArray(), 0); } + // str[0...i-1]已经转化完了,固定了 // i之前的位置,如何转化已经做过决定了, 不用再关心 // i... 有多少种转化的结果 public static int process(char[] str, int i) { @@ -19,6 +20,8 @@ public class Code06_ConvertToLetterString { if (str[i] == '0') { return 0; } + + // i没有到终止位置 // str[i]字符不是‘0’ if (str[i] == '1') { int res = process(str, i + 1); // i自己作为单独的部分,后续有多少种方法 diff --git a/src/class11/Code07_Knapsack.java b/src/class11/Code07_Knapsack.java index 6ae4b46..76e0616 100644 --- a/src/class11/Code07_Knapsack.java +++ b/src/class11/Code07_Knapsack.java @@ -6,7 +6,11 @@ public class Code07_Knapsack { return process(w, v, 0, 0, bag); } + // 不变 : w[] v[] bag // index... 最大价值 + // 0..index-1上做了货物的选择,使得你已经达到的重量是多少alreadyW + // 如果返回-1,认为没有方案 + // 如果不返回-1,认为返回的值是真实价值 public static int process(int[] w, int[] v, int index, int alreadyW, int bag) { if (alreadyW > bag) { return -1; @@ -30,11 +34,11 @@ public class Code07_Knapsack { } // 只剩下rest的空间了, - // index...货物自由选择,但是不要超过rest的空间 - // 返回能够获得的最大价值 + // index...货物自由选择,但是剩余空间不要小于0 + // 返回 index...货物能够获得的最大价值 public static int process(int[] w, int[] v, int index, int rest) { - if (rest <= 0) { // base case 1 - return 0; + if (rest < 0) { // base case 1 + return -1; } // rest >=0 if (index == w.length) { // base case 2 @@ -42,9 +46,10 @@ public class Code07_Knapsack { } // 有货也有空间 int p1 = process(w, v, index + 1, rest); - int p2 = Integer.MIN_VALUE; - if (rest >= w[index]) { - p2 = v[index] + process(w, v, index + 1, rest - w[index]); + int p2 = -1; + int p2Next = process(w, v, index + 1, rest - w[index]); + if(p2Next!=-1) { + p2 = v[index] + p2Next; } return Math.max(p1, p2); } diff --git a/src/class11/Code08_CardsInLine.java b/src/class11/Code08_CardsInLine.java index 7ee3451..a53a53e 100644 --- a/src/class11/Code08_CardsInLine.java +++ b/src/class11/Code08_CardsInLine.java @@ -6,21 +6,32 @@ public class Code08_CardsInLine { if (arr == null || arr.length == 0) { return 0; } - return Math.max(f(arr, 0, arr.length - 1), s(arr, 0, arr.length - 1)); + return Math.max( + f(arr, 0, arr.length - 1), + s(arr, 0, arr.length - 1) + ); } - public static int f(int[] arr, int i, int j) { - if (i == j) { - return arr[i]; + public static int f(int[] arr, int L, int R) { + if (L == R) { + return arr[L]; } - return Math.max(arr[i] + s(arr, i + 1, j), arr[j] + s(arr, i, j - 1)); + + return Math.max( + arr[L] + s(arr, L + 1, R), + arr[R] + s(arr, L, R - 1) + ); } + // i..j public static int s(int[] arr, int i, int j) { if (i == j) { return 0; } - return Math.min(f(arr, i + 1, j), f(arr, i, j - 1)); + return Math.min( + f(arr, i + 1, j), // arr[i] + f(arr, i, j - 1) // arr[j] + ); } public static int win2(int[] arr) { @@ -40,9 +51,11 @@ public class Code08_CardsInLine { } public static void main(String[] args) { - int[] arr = { 1, 9, 1 }; - System.out.println(win1(arr)); - System.out.println(win2(arr)); + int[] arr = { 4,7,9,5 }; + // A 4 9 + // B 7 5 + System.out.println(f(arr,0,3)); + System.out.println(s(arr,0,3)); } diff --git a/src/class11/Code09_NQueens.java b/src/class11/Code09_NQueens.java index 357f698..8868d2c 100644 --- a/src/class11/Code09_NQueens.java +++ b/src/class11/Code09_NQueens.java @@ -14,12 +14,13 @@ public class Code09_NQueens { // 潜台词:record[0..i-1]的皇后,任何两个皇后一定都不共行、不共列,不共斜线 // 目前来到了第i行 // record[0..i-1]表示之前的行,放了的皇后位置 - // n代表整体一共有多少行 + // n代表整体一共有多少行 0~n-1行 // 返回值是,摆完所有的皇后,合理的摆法有多少种 public static int process1(int i, int[] record, int n) { if (i == n) { // 终止行 return 1; } + // 没有到终止位置,还有皇后要摆 int res = 0; for (int j = 0; j < n; j++) { // 当前行在i行,尝试i行所有的列 -> j // 当前i行的皇后,放在j列,会不会和之前(0..i-1)的皇后,不共行共列或者共斜线, @@ -36,7 +37,8 @@ public class Code09_NQueens { // record[0..i-1]你需要看,record[i...]不需要看 // 返回i行皇后,放在了j列,是否有效 public static boolean isValid(int[] record, int i, int j) { - for (int k = 0; k < i; k++) { // 之前的某个k行的皇后 + for (int k = 0; k < i; k++) { // 之前的某个k行的皇后 + // k, record[k] i, j if (j == record[k] || Math.abs(record[k] - j) == Math.abs(i - k)) { return false; } @@ -49,25 +51,32 @@ public class Code09_NQueens { if (n < 1 || n > 32) { return 0; } + // 如果你是13皇后问题,limit 最右13个1,其他都是0 int limit = n == 32 ? -1 : (1 << n) - 1; return process2(limit, 0, 0, 0); } + // limit 划定了问题的规模 -> 固定 + // colLim 列的限制,1的位置不能放皇后,0的位置可以 // leftDiaLim 左斜线的限制,1的位置不能放皇后,0的位置可以 // rightDiaLim 右斜线的限制,1的位置不能放皇后,0的位置可以 - public static int process2(int limit, + public static int process2( + int limit, int colLim, int leftDiaLim, int rightDiaLim) { if (colLim == limit) { // base case return 1; } - // 所有候选皇后的位置,都在pos上 - int pos = limit & (~(colLim | leftDiaLim | rightDiaLim)); + // 所有可以放皇后的位置,都在pos上 + // colLim | leftDiaLim | rightDiaLim -> 总限制 + // ~ (colLim | leftDiaLim | rightDiaLim) -> 左侧的一坨0干扰,右侧每个1,可尝试 + int pos = limit & ( ~(colLim | leftDiaLim | rightDiaLim) ); int mostRightOne = 0; int res = 0; while (pos != 0) { + // 其取出pos中,最右侧的1来,剩下位置都是0 mostRightOne = pos & (~pos + 1); pos = pos - mostRightOne; res += process2(limit, @@ -79,7 +88,7 @@ public class Code09_NQueens { } public static void main(String[] args) { - int n = 14; + int n = 15; long start = System.currentTimeMillis(); System.out.println(num2(n)); diff --git a/src/class12/Code01_RobotWalk.java b/src/class12/Code01_RobotWalk.java index ef8bcd3..2a9ff14 100644 --- a/src/class12/Code01_RobotWalk.java +++ b/src/class12/Code01_RobotWalk.java @@ -39,6 +39,58 @@ public class Code01_RobotWalk { // 走向左、走向右是截然不同的方法,所以总方法数要都算上 return walk(N, cur + 1, rest - 1, P) + walk(N, cur - 1, rest - 1, P); } + + + + + + + public static int waysCache(int N, int M, int K, int P) { + // 参数无效直接返回0 + if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { + return 0; + } + + int[][] dp = new int[N+1][K+1]; + for(int row = 0; row <= N; row++) { + for(int col = 0; col <= K; col++) { + dp[row][col] = -1; + } + } + return walkCache(N, M, K, P,dp); + } + + // HashMap (19,100) "19_100" + // 我想把所有cur和rest的组合,返回的结果,加入到缓存里 + public static int walkCache(int N, int cur, int rest, int P, int[][] dp) { + if(dp[cur][rest] != -1) { + return dp[cur][rest]; + } + if (rest == 0) { + dp[cur][rest] = cur == P ? 1 : 0; + return dp[cur][rest]; + } + if (cur == 1) { + dp[cur][rest] = walkCache(N, 2, rest - 1, P, dp); + return dp[cur][rest]; + } + if (cur == N) { + dp[cur][rest] =walkCache(N, N - 1, rest - 1, P,dp); + return dp[cur][rest]; + } + dp[cur][rest] = walkCache(N, cur + 1, rest - 1, P,dp) + + walkCache(N, cur - 1, rest - 1, P, dp); + return dp[cur][rest]; + } + + + + + + + + + public static int ways2(int N, int M, int K, int P) { // 参数无效直接返回0 diff --git a/src/class12/Code03_Knapsack.java b/src/class12/Code03_Knapsack.java index 23c7a87..b695371 100644 --- a/src/class12/Code03_Knapsack.java +++ b/src/class12/Code03_Knapsack.java @@ -33,8 +33,8 @@ public class Code03_Knapsack { // index...货物自由选择,但是不要超过rest的空间 // 返回能够获得的最大价值 public static int process(int[] w, int[] v, int index, int rest) { - if (rest <= 0) { // base case 1 - return 0; + if (rest < 0) { // base case 1 + return -1; } // rest >=0 if (index == w.length) { // base case 2 @@ -42,9 +42,10 @@ public class Code03_Knapsack { } // 有货也有空间 int p1 = process(w, v, index + 1, rest); - int p2 = Integer.MIN_VALUE; - if (rest >= w[index]) { - p2 = v[index] + process(w, v, index + 1, rest - w[index]); + int p2 = -1; + int p2Next = process(w, v, index + 1, rest - w[index]); + if(p2Next!=-1) { + p2 = v[index] + p2Next; } return Math.max(p1, p2); }