diff --git a/src/class18/Code01_RobotWalk.java b/src/class18/Code01_RobotWalk.java index f86fe3b..f9ee3f2 100644 --- a/src/class18/Code01_RobotWalk.java +++ b/src/class18/Code01_RobotWalk.java @@ -2,148 +2,93 @@ package class18; public class Code01_RobotWalk { - public static int ways1(int N, int M, int K, int P) { - if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { - return 0; + public static int ways1(int N, int start, int aim, int K) { + if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) { + return -1; } - return walk(N, M, K, P); + return process1(start, K, aim, N); } - public static int walk(int N, int cur, int rest, int P) { - if (rest == 0) { - return cur == P ? 1 : 0; - } - if (cur == 1) { - return walk(N, 2, rest - 1, P); - } - if (cur == N) { - return walk(N, N - 1, rest - 1, P); - } - return walk(N, cur + 1, rest - 1, P) + walk(N, cur - 1, rest - 1, P); + // 机器人当前来到的位置是cur, + // 机器人还有rest步需要去走, + // 最终的目标是aim, + // 有哪些位置?1~N + // 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少? + public static int process1(int cur, int rest, int aim, int N) { + if (rest == 0) { // 如果已经不需要走了,走完了! + return cur == aim ? 1 : 0; + } + // (cur, rest) + if (cur == 1) { // 1 -> 2 + return process1(2, rest - 1, aim, N); + } + // (cur, rest) + if (cur == N) { // N-1 <- N + return process1(N - 1, rest - 1, aim, N); + } + // (cur, rest) + return process1(cur - 1, rest - 1, aim, N) + process1(cur + 1, rest - 1, aim, N); } - public static int waysCache(int N, int M, int K, int P) { - if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { - return 0; + public static int ways2(int N, int start, int aim, int K) { + if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) { + return -1; } 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; + for (int i = 0; i <= N; i++) { + for (int j = 0; j <= K; j++) { + dp[i][j] = -1; } } - return walkCache(N, M, K, P, dp); + // dp就是缓存表 + // dp[cur][rest] == -1 -> process1(cur, rest)之前没算过! + // dp[cur][rest] != -1 -> process1(cur, rest)之前算过!返回值,dp[cur][rest] + // N+1 * K+1 + return process2(start, K, aim, N, dp); } - public static int walkCache(int N, int cur, int rest, int P, int[][] dp) { + // cur 范: 1 ~ N + // rest 范:0 ~ K + public static int process2(int cur, int rest, int aim, int N, int[][] dp) { if (dp[cur][rest] != -1) { return dp[cur][rest]; } + // 之前没算过! + int ans = 0; 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) { - if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { - return 0; - } - int[][] dp = new int[K + 1][N + 1]; - dp[0][P] = 1; - for (int i = 1; i <= K; i++) { - for (int j = 1; j <= N; j++) { - if (j == 1) { - dp[i][j] = dp[i - 1][2]; - } else if (j == N) { - dp[i][j] = dp[i - 1][N - 1]; - } else { - dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1]; - } - } - } - return dp[K][M]; - } - - public static int ways3(int N, int M, int K, int P) { - if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { - return 0; - } - int[] dp = new int[N + 1]; - dp[P] = 1; - for (int i = 1; i <= K; i++) { - int leftUp = dp[1]; - for (int j = 1; j <= N; j++) { - int tmp = dp[j]; - if (j == 1) { - dp[j] = dp[j + 1]; - } else if (j == N) { - dp[j] = leftUp; - } else { - dp[j] = leftUp + dp[j + 1]; - } - leftUp = tmp; - } - } - return dp[M]; - } + ans = cur == aim ? 1 : 0; + } else if (cur == 1) { + ans = process2(2, rest - 1, aim, N, dp); + } else if (cur == N) { + ans = process2(N - 1, rest - 1, aim, N, dp); + } else { + ans = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp); + } + dp[cur][rest] = ans; + return ans; - public static int ways4(int N, int M, int K, int P) { - if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { - return 0; - } - return process(N, 0, P, M, K); } - public static int process(int N, int i, int j, int M, int K) { - if (i == K) { - return j == M ? 1 : 0; - } - if (j == 1) { - return process(N, i + 1, j + 1, M, K); + public static int ways3(int N, int start, int aim, int K) { + if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) { + return -1; } - if (j == N) { - return process(N, i + 1, j - 1, M, K); - } - return process(N, i + 1, j + 1, M, K) + process(N, i + 1, j - 1, M, K); - } - - public static int ways5(int N, int M, int K, int P) { - if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) { - return 0; - } - int[][] dp = new int[K + 1][N + 1]; - dp[K][M] = 1; - for (int i = K - 1; i >= 0; i--) { - for (int j = 1; j <= N; j++) { - if (j == 1) { - dp[i][j] = dp[i + 1][j + 1]; - } else if (j == N) { - dp[i][j] = dp[i + 1][j - 1]; - } else { - dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j - 1]; - } + int[][] dp = new int[N + 1][K + 1]; + dp[aim][0] = 1; + for (int rest = 1; rest <= K; rest++) { + dp[1][rest] = dp[2][rest - 1]; + for (int cur = 2; cur < N; cur++) { + dp[cur][rest] = dp[cur - 1][rest - 1] + dp[cur + 1][rest - 1]; } + dp[N][rest] = dp[N - 1][rest - 1]; } - return dp[0][P]; + return dp[start][K]; } public static void main(String[] args) { - System.out.println(ways1(7, 4, 9, 5)); - System.out.println(ways2(7, 4, 9, 5)); - System.out.println(ways3(7, 4, 9, 5)); - System.out.println(ways4(7, 4, 9, 5)); - System.out.println(ways5(7, 4, 9, 5)); + System.out.println(ways1(5, 2, 4, 6)); + System.out.println(ways2(5, 2, 4, 6)); + System.out.println(ways3(5, 2, 4, 6)); } } diff --git a/src/class18/Code02_CardsInLine.java b/src/class18/Code02_CardsInLine.java new file mode 100644 index 0000000..919a4cb --- /dev/null +++ b/src/class18/Code02_CardsInLine.java @@ -0,0 +1,116 @@ +package class18; + +public class Code02_CardsInLine { + + // 根据规则,返回获胜者的分数 + public static int win1(int[] arr) { + if (arr == null || arr.length == 0) { + return 0; + } + int first = f1(arr, 0, arr.length - 1); + int second = g1(arr, 0, arr.length - 1); + return Math.max(first, second); + } + + // arr[L..R],先手获得的最好分数返回 + public static int f1(int[] arr, int L, int R) { + if (L == R) { + return arr[L]; + } + int p1 = arr[L] + g1(arr, L + 1, R); + int p2 = arr[R] + g1(arr, L, R - 1); + return Math.max(p1, p2); + } + + // // arr[L..R],后手获得的最好分数返回 + public static int g1(int[] arr, int L, int R) { + if (L == R) { + return 0; + } + int p1 = f1(arr, L + 1, R); // 对手拿走了L位置的数 + int p2 = f1(arr, L, R - 1); // 对手拿走了R位置的数 + return Math.min(p1, p2); + } + + public static int win2(int[] arr) { + if (arr == null || arr.length == 0) { + return 0; + } + int N = arr.length; + int[][] fmap = new int[N][N]; + int[][] gmap = new int[N][N]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + fmap[i][j] = -1; + gmap[i][j] = -1; + } + } + int first = f2(arr, 0, arr.length - 1, fmap, gmap); + int second = g2(arr, 0, arr.length - 1, fmap, gmap); + return Math.max(first, second); + } + + // arr[L..R],先手获得的最好分数返回 + public static int f2(int[] arr, int L, int R, int[][] fmap, int[][] gmap) { + if (fmap[L][R] != -1) { + return fmap[L][R]; + } + int ans = 0; + if (L == R) { + ans = arr[L]; + } else { + int p1 = arr[L] + g2(arr, L + 1, R, fmap, gmap); + int p2 = arr[R] + g2(arr, L, R - 1, fmap, gmap); + ans = Math.max(p1, p2); + } + fmap[L][R] = ans; + return ans; + } + + // // arr[L..R],后手获得的最好分数返回 + public static int g2(int[] arr, int L, int R, int[][] fmap, int[][] gmap) { + if (gmap[L][R] != -1) { + return gmap[L][R]; + } + int ans = 0; + if (L != R) { + int p1 = f2(arr, L + 1, R, fmap, gmap); // 对手拿走了L位置的数 + int p2 = f2(arr, L, R - 1, fmap, gmap); // 对手拿走了R位置的数 + ans = Math.min(p1, p2); + } + gmap[L][R] = ans; + return ans; + } + + public static int win3(int[] arr) { + if (arr == null || arr.length == 0) { + return 0; + } + int N = arr.length; + int[][] fmap = new int[N][N]; + int[][] gmap = new int[N][N]; + for (int i = 0; i < N; i++) { + fmap[i][i] = arr[i]; + } + for (int startCol = 1; startCol < N; startCol++) { + int L = 0; + int R = startCol; + while (R < N) { + fmap[L][R] = Math.max(arr[L] + gmap[L + 1][R], arr[R] + gmap[L][R - 1]); + gmap[L][R] = Math.min(fmap[L + 1][R], fmap[L][R - 1]); + L++; + R++; + } + } + return Math.max(fmap[0][N - 1], gmap[0][N - 1]); + } + + public static void main(String[] args) { + int[] arr = { 5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7 }; + System.out.println(win1(arr)); + System.out.println(win2(arr)); + System.out.println(win3(arr)); + + } + +} diff --git a/src/class18/Code03_CardsInLine.java b/src/class18/Code03_CardsInLine.java deleted file mode 100644 index 4d74b32..0000000 --- a/src/class18/Code03_CardsInLine.java +++ /dev/null @@ -1,56 +0,0 @@ -package class18; - -public class Code03_CardsInLine { - - public static int win1(int[] arr) { - if (arr == null || arr.length == 0) { - return 0; - } - return Math.max(f(arr, 0, arr.length - 1), s(arr, 0, arr.length - 1)); - } - - public static int f(int[] arr, int L, int R) { - if (L == R) { - return arr[L]; - } - return Math.max(arr[L] + s(arr, L + 1, R), arr[R] + s(arr, L, R - 1)); - } - - public static int s(int[] arr, int L, int R) { - if (L == R) { - return 0; - } - return Math.min(f(arr, L + 1, R), f(arr, L, R - 1)); - } - - public static int windp(int[] arr) { - if (arr == null || arr.length == 0) { - return 0; - } - int N = arr.length; - int[][] f = new int[N][N]; - int[][] s = new int[N][N]; - for (int i = 0; i < N; i++) { - f[i][i] = arr[i]; - } - for (int col = 1; col < N; col++) { - int L = 0; - int R = col; - while (L < N && R < N) { - f[L][R] = Math.max(arr[L] + s[L + 1][R], arr[R] + s[L][R - 1]); - s[L][R] = Math.min(f[L + 1][R], f[L][R - 1]); - L++; - R++; - } - } - return Math.max(f[0][N - 1], s[0][N - 1]); - } - - public static void main(String[] args) { - int[] arr = { 5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7 }; - System.out.println(win1(arr)); - System.out.println(windp(arr)); - - } - -} diff --git a/src/class18/Code02_Knapsack.java b/src/class18/Code03_Knapsack.java similarity index 98% rename from src/class18/Code02_Knapsack.java rename to src/class18/Code03_Knapsack.java index 0bcb2e0..d80c76e 100644 --- a/src/class18/Code02_Knapsack.java +++ b/src/class18/Code03_Knapsack.java @@ -1,6 +1,6 @@ package class18; -public class Code02_Knapsack { +public class Code03_Knapsack { public static int getMaxValue(int[] w, int[] v, int bag) { return process(w, v, 0, 0, bag); diff --git a/src/class18/Code05_StickersToSpellWord.java b/src/class18/Code05_StickersToSpellWord.java index 5e574c8..fcb375c 100644 --- a/src/class18/Code05_StickersToSpellWord.java +++ b/src/class18/Code05_StickersToSpellWord.java @@ -72,7 +72,7 @@ public class Code05_StickersToSpellWord { int min = Integer.MAX_VALUE; for (int i = 0; i < N; i++) { int[] sticker = stickers[i]; - // 关键优化(重要的剪枝!这一步也是贪心!) + // 最关键的优化(重要的剪枝!这一步也是贪心!) if (sticker[target[0] - 'a'] > 0) { StringBuilder builder = new StringBuilder(); for (int j = 0; j < 26; j++) {