diff --git a/src/class19/Code02_PalindromeSubsequence.java b/src/class19/Code02_PalindromeSubsequence.java index 90d93ed..94cf109 100644 --- a/src/class19/Code02_PalindromeSubsequence.java +++ b/src/class19/Code02_PalindromeSubsequence.java @@ -1,38 +1,75 @@ package class19; +// 测试链接:https://leetcode.com/problems/longest-palindromic-subsequence/ public class Code02_PalindromeSubsequence { - public static int lcse(char[] str1, char[] str2) { - - - - - int[][] dp = new int[str1.length][str2.length]; - - - + public static int longestPalindromeSubseq1(String s) { + if (s == null || s.length() == 0) { + return 0; + } + if (s.length() == 1) { + return 1; + } + char[] str = s.toCharArray(); + char[] reverse = reverse(str); + return longestCommonSubsequence(str, reverse); + } + + public static char[] reverse(char[] str) { + int N = str.length; + char[] reverse = new char[str.length]; + for (int i = 0; i < str.length; i++) { + reverse[--N] = str[i]; + } + return reverse; + } + + public static int longestCommonSubsequence(char[] str1, char[] str2) { + int N = str1.length; + int M = str2.length; + int[][] dp = new int[N][M]; dp[0][0] = str1[0] == str2[0] ? 1 : 0; - - - for (int i = 1; i < str1.length; i++) { - dp[i][0] = Math.max(dp[i - 1][0], str1[i] == str2[0] ? 1 : 0); + for (int i = 1; i < N; i++) { + dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0]; } - for (int j = 1; j < str2.length; j++) { - dp[0][j] = Math.max(dp[0][j - 1], str1[0] == str2[j] ? 1 : 0); + for (int j = 1; j < M; j++) { + dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1]; } - for (int i = 1; i < str1.length; i++) { - for (int j = 1; j < str2.length; j++) { + for (int i = 1; i < N; i++) { + for (int j = 1; j < M; j++) { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); if (str1[i] == str2[j]) { dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1); - } + } } } - return dp[str1.length - 1][str2.length - 1]; + return dp[N - 1][M - 1]; } - public static void main(String[] args) { - + public static int longestPalindromeSubseq2(String s) { + if (s == null || s.length() == 0) { + return 0; + } + if (s.length() == 1) { + return 1; + } + char[] str = s.toCharArray(); + int N = str.length; + int[][] dp = new int[N][N]; + dp[N - 1][N - 1] = 1; + for (int i = 0; i < N - 1; i++) { + dp[i][i] = 1; + dp[i][i + 1] = str[i] == str[i + 1] ? 2 : 1; + } + for (int i = N - 3; i >= 0; i--) { + for (int j = i + 2; j < N; j++) { + dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]); + if (str[i] == str[j]) { + dp[i][j] = Math.max(dp[i][j], dp[i + 1][j - 1] + 2); + } + } + } + return dp[0][N - 1]; } } diff --git a/src/class19/Code03_HorseJump.java b/src/class19/Code03_HorseJump.java index f48df78..a560edd 100644 --- a/src/class19/Code03_HorseJump.java +++ b/src/class19/Code03_HorseJump.java @@ -2,15 +2,10 @@ package class19; public class Code03_HorseJump { - // 10*9 - // 0~9 y - // 0~8 x public static int ways(int a, int b, int step) { return f(0, 0, step, a, b); } - // 马在(i,j)位置,还有step步要去跳 - // 返回最终来到(a,b)的方法数 public static int f(int i, int j, int step, int a, int b) { if (i < 0 || i > 9 || j < 0 || j > 8) { return 0; @@ -31,7 +26,6 @@ public class Code03_HorseJump { public static int waysdp(int a, int b, int s) { - // (i,j,0~ step) int[][][] dp = new int[10][9][s+1]; dp[a][b][0] = 1; for(int step = 1 ; step <= s;step++ ) { // 按层来 diff --git a/src/class20/Code01_CoinsWayEveryPaperDifferent.java b/src/class20/Code01_CoinsWayEveryPaperDifferent.java index 3cf9b71..008910d 100644 --- a/src/class20/Code01_CoinsWayEveryPaperDifferent.java +++ b/src/class20/Code01_CoinsWayEveryPaperDifferent.java @@ -1,8 +1,5 @@ package class20; -// arr是货币数组,其中的值都是正数,每个值都认为是一张货币, -// 即便是值相同的货币认为每一张都是独立且不同的, -// 返回组成aim的方法数 public class Code01_CoinsWayEveryPaperDifferent { public static int coinWays(int[] arr, int aim) { @@ -64,7 +61,7 @@ public class Code01_CoinsWayEveryPaperDifferent { int aim = (int) (Math.random() * maxValue); int ans1 = coinWays(arr, aim); int ans2 = dp(arr, aim); - if (ans1 == ans2) { + if (ans1 != ans2) { System.out.println("Oops!"); printArray(arr); System.out.println(aim); diff --git a/src/class20/Code02_CoinsWayNoLimit.java b/src/class20/Code02_CoinsWayNoLimit.java index c52ca70..95dd573 100644 --- a/src/class20/Code02_CoinsWayNoLimit.java +++ b/src/class20/Code02_CoinsWayNoLimit.java @@ -1,7 +1,5 @@ package class20; -// arr是面值数组,其中的值都是正数且无重复值, -// 每张面值可以用无限张,返回组成aim的方法数 public class Code02_CoinsWayNoLimit { public static int coinsWay(int[] arr, int aim) { diff --git a/src/class20/Code03_CoinsWaySameValueSamePapper.java b/src/class20/Code03_CoinsWaySameValueSamePapper.java index ad316c7..357fb37 100644 --- a/src/class20/Code03_CoinsWaySameValueSamePapper.java +++ b/src/class20/Code03_CoinsWaySameValueSamePapper.java @@ -3,9 +3,6 @@ package class20; import java.util.HashMap; import java.util.Map.Entry; -// arr是货币数组,其中的值都是正数,每个值都认为是一张货币, -// 值相同的货币认为每一张都没有不同! -// 返回组成aim的方法数 public class Code03_CoinsWaySameValueSamePapper { public static class Info { diff --git a/src/class20/Code04_MinCoinsOnePaper.java b/src/class20/Code04_MinCoinsOnePaper.java index 23958f9..02e48a1 100644 --- a/src/class20/Code04_MinCoinsOnePaper.java +++ b/src/class20/Code04_MinCoinsOnePaper.java @@ -4,8 +4,6 @@ import java.util.HashMap; import java.util.Map.Entry; import java.util.LinkedList; -// arr中的每个值都代表一张钱 -// arr中都是正数,aim>=0,返回组成aim的最小张数 public class Code04_MinCoinsOnePaper { public static int minCoins(int[] arr, int aim) { diff --git a/src/class20/Code05_MinCoinsNoLimit.java b/src/class20/Code05_MinCoinsNoLimit.java index cb0f19c..b41ad45 100644 --- a/src/class20/Code05_MinCoinsNoLimit.java +++ b/src/class20/Code05_MinCoinsNoLimit.java @@ -1,7 +1,5 @@ package class20; -// arr是面值数组,其中的值都是正数且无重复值, -// 每张面值可以用无限张,返回组成aim的最少货币数 public class Code05_MinCoinsNoLimit { public static int minCoins(int[] arr, int aim) { diff --git a/src/class21/Code02_KillMonster.java b/src/class21/Code02_KillMonster.java index 191dcbc..fbc2871 100644 --- a/src/class21/Code02_KillMonster.java +++ b/src/class21/Code02_KillMonster.java @@ -1,6 +1,5 @@ package class21; -// 题目描述看包里KillMonster.jpeg public class Code02_KillMonster { public static double right1(int N, int M, int K) { diff --git a/src/class21/Code03_SplitSumClosed.java b/src/class21/Code03_SplitSumClosed.java index e8eccfd..c9bb573 100644 --- a/src/class21/Code03_SplitSumClosed.java +++ b/src/class21/Code03_SplitSumClosed.java @@ -2,12 +2,6 @@ package class21; import java.util.TreeSet; -/* - * 给定一个整型数组arr,请把arr中所有的数分成两个集合,尽量让两个集合的累加和接近 - * 返回最接近的情况下,较小集合的累加和(较大集合的累加和一定是所有数累加和减去较小集合的累加和) - * 为了方便起见,假设arr中没有负数,其实也可以有 - * 但是处理起来会比较麻烦,而且有没有负数都不影响算法流程的理解 - * */ public class Code03_SplitSumClosed { public static int right(int[] arr) { diff --git a/src/class21/Code04_SplitSumClosedSizeHalf.java b/src/class21/Code04_SplitSumClosedSizeHalf.java index a652fe4..bdfffff 100644 --- a/src/class21/Code04_SplitSumClosedSizeHalf.java +++ b/src/class21/Code04_SplitSumClosedSizeHalf.java @@ -2,15 +2,6 @@ package class21; import java.util.TreeSet; -/* - * 给定一个整型数组arr,请把arr中所有的数分成两个集合 - * 如果arr长度为偶数,两个集合包含数的个数要一样多 - * 如果arr长度为奇数,两个集合包含数的个数必须只差一个 - * 请尽量让两个集合的累加和接近 - * 返回最接近的情况下,较小集合的累加和(较大集合的累加和一定是所有数累加和减去较小集合的累加和) - * 为了方便起见,假设arr中没有负数,其实也可以有 - * 但是处理起来会比较麻烦,而且有没有负数都不影响算法流程的理解 - * */ public class Code04_SplitSumClosedSizeHalf { public static int right(int[] arr) { diff --git a/src/class21/Code05_NQueens.java b/src/class21/Code05_NQueens.java index e8aab39..de49c7a 100644 --- a/src/class21/Code05_NQueens.java +++ b/src/class21/Code05_NQueens.java @@ -6,26 +6,16 @@ public class Code05_NQueens { if (n < 1) { return 0; } - // record[0] ? record[1] ? record[2] - int[] record = new int[n]; // record[i] -> i行的皇后,放在了第几列 + int[] record = new int[n]; return process1(0, record, n); } - // 潜台词:record[0..i-1]的皇后,任何两个皇后一定都不共行、不共列,不共斜线 - // 目前来到了第i行 - // record[0..i-1]表示之前的行,放了的皇后位置 - // n代表整体一共有多少行 0~n-1行 - // 返回值是,摆完所有的皇后,合理的摆法有多少种 public static int process1(int i, int[] record, int n) { - if (i == n) { // 终止行 + if (i == n) { return 1; } - // 没有到终止位置,还有皇后要摆 int res = 0; - for (int j = 0; j < n; j++) { // 当前行在i行,尝试i行所有的列 -> j - // 当前i行的皇后,放在j列,会不会和之前(0..i-1)的皇后,不共行共列或者共斜线, - // 如果是,认为有效 - // 如果不是,认为无效 + for (int j = 0; j < n; j++) { if (isValid(record, i, j)) { record[i] = j; res += process1(i + 1, record, n); @@ -34,11 +24,8 @@ public class Code05_NQueens { return res; } - // 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行的皇后 - // k, record[k] i, j + for (int k = 0; k < i; k++) { if (j == record[k] || Math.abs(record[k] - j) == Math.abs(i - k)) { return false; } @@ -56,27 +43,18 @@ public class Code05_NQueens { return process2(limit, 0, 0, 0); } - // limit 划定了问题的规模 -> 固定 - - // colLim 列的限制,1的位置不能放皇后,0的位置可以 - // leftDiaLim 左斜线的限制,1的位置不能放皇后,0的位置可以 - // rightDiaLim 右斜线的限制,1的位置不能放皇后,0的位置可以 public static int process2( int limit, int colLim, int leftDiaLim, int rightDiaLim) { - if (colLim == limit) { // base case + if (colLim == limit) { return 1; } - // 所有可以放皇后的位置,都在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, diff --git a/src/class21/KillMonster.jpeg b/src/class21/KillMonster.jpeg deleted file mode 100644 index 5e69a2b..0000000 Binary files a/src/class21/KillMonster.jpeg and /dev/null differ