diff --git a/src/class46/Code01_BurstBalloons.java b/src/class46/Code01_BurstBalloons.java index cfaf361..71d2602 100644 --- a/src/class46/Code01_BurstBalloons.java +++ b/src/class46/Code01_BurstBalloons.java @@ -3,6 +3,43 @@ package class46; // 本题测试链接 : https://leetcode.com/problems/burst-balloons/ public class Code01_BurstBalloons { + public static int maxCoins0(int[] arr) { + // [3,2,1,3] + // [1,3,2,1,3,1] + int N = arr.length; + int[] help = new int[N + 2]; + for (int i = 0; i < N; i++) { + help[i + 1] = arr[i]; + } + help[0] = 1; + help[N + 1] = 1; + return func(help, 1, N); + } + + // L-1位置,和R+1位置,永远不越界,并且,[L-1] 和 [R+1] 一定没爆呢! + // 返回,arr[L...R]打爆所有气球,最大得分是什么 + public static int func(int[] arr, int L, int R) { + if (L == R) { + return arr[L - 1] * arr[L] * arr[R + 1]; + } + // 尝试每一种情况,最后打爆的气球,是什么位置 + // L...R + // L位置的气球,最后打爆 + int max = func(arr, L + 1, R) + arr[L - 1] * arr[L] * arr[R + 1]; + // R位置的气球,最后打爆 + max = Math.max(max, func(arr, L, R - 1) + arr[L - 1] * arr[R] * arr[R + 1]); + // 尝试所有L...R,中间的位置,(L,R) + for (int i = L + 1; i < R; i++) { + // i位置的气球,最后打爆 + int left = func(arr, L, i - 1); + int right = func(arr, i + 1, R); + int last = arr[L - 1] * arr[i] * arr[R + 1]; + int cur = left + right + last; + max = Math.max(max, cur); + } + return max; + } + public static int maxCoins1(int[] arr) { if (arr == null || arr.length == 0) { return 0; diff --git a/src/class46/Code02_RemoveBoxes.java b/src/class46/Code02_RemoveBoxes.java index 75f5a84..8db4d8f 100644 --- a/src/class46/Code02_RemoveBoxes.java +++ b/src/class46/Code02_RemoveBoxes.java @@ -3,6 +3,23 @@ package class46; // 本题测试链接 : https://leetcode.com/problems/remove-boxes/ public class Code02_RemoveBoxes { + // arr[L...R]消除,而且前面跟着K个arr[L]这个数 + // 返回:所有东西都消掉,最大得分 + public static int func1(int[] arr, int L, int R, int K) { + if (L > R) { + return 0; + } + int ans = func1(arr, L + 1, R, 0) + (K + 1) * (K + 1); + + // 前面的K个X,和arr[L]数,合在一起了,现在有K+1个arr[L]位置的数 + for (int i = L + 1; i <= R; i++) { + if (arr[i] == arr[L]) { + ans = Math.max(ans, func1(arr, L + 1, i - 1, 0) + func1(arr, i, R, K + 1)); + } + } + return ans; + } + public static int removeBoxes1(int[] boxes) { int N = boxes.length; int[][][] dp = new int[N][N][N]; @@ -41,10 +58,15 @@ public class Code02_RemoveBoxes { if (dp[L][R][K] > 0) { return dp[L][R][K]; } + // 找到开头, + // 1,1,1,1,1,5 + // 3 4 5 6 7 8 + // ! int last = L; while (last + 1 <= R && boxes[last + 1] == boxes[L]) { last++; } + // K个1 (K + last - L) last int pre = K + last - L; int ans = (pre + 1) * (pre + 1) + process2(boxes, last + 1, R, 0, dp); for (int i = last + 2; i <= R; i++) { diff --git a/src/class46/Code03_DeleteAdjacentSameCharacter.java b/src/class46/Code03_DeleteAdjacentSameCharacter.java index f0aa370..0b1e7f3 100644 --- a/src/class46/Code03_DeleteAdjacentSameCharacter.java +++ b/src/class46/Code03_DeleteAdjacentSameCharacter.java @@ -59,6 +59,9 @@ public class Code03_DeleteAdjacentSameCharacter { return process(str, 0, str.length - 1, false); } + // str[L...R] 前面有没有跟着[L]字符,has T 有 F 无 + // L,R,has + // 最少能剩多少字符,消不了 public static int process(char[] str, int L, int R, boolean has) { if (L > R) { return 0; @@ -72,6 +75,7 @@ public class Code03_DeleteAdjacentSameCharacter { K++; index++; } + // index表示,第一个不是[L]字符的位置 int way1 = (K > 1 ? 0 : 1) + process(str, index, R, false); int way2 = Integer.MAX_VALUE; for (int split = index; split <= R; split++) { diff --git a/src/class46/HuffmanTree.java b/src/class46/HuffmanTree.java new file mode 100644 index 0000000..78bd545 --- /dev/null +++ b/src/class46/HuffmanTree.java @@ -0,0 +1,214 @@ +package class46; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.PriorityQueue; + +// 本文件不牵扯任何byte类型的转化 +// 怎么转byte自己来,我只负责huffman算法本身的正确实现 +// 字符串为空的时候,自己处理边界吧 +// 实现的代码通过了大样本随机测试的对数器 +// 可以从main函数的内容开始看起 +public class HuffmanTree { + + // 根据文章str, 生成词频统计表 + public static HashMap countMap(String str) { + HashMap ans = new HashMap<>(); + char[] s = str.toCharArray(); + for (char cha : s) { + if (!ans.containsKey(cha)) { + ans.put(cha, 1); + } else { + ans.put(cha, ans.get(cha) + 1); + } + } + return ans; + } + + public static class Node { + public int count; + public Node left; + public Node right; + + public Node(int c) { + count = c; + } + } + + public static class NodeComp implements Comparator { + + @Override + public int compare(Node o1, Node o2) { + return o1.count - o2.count; + } + + } + + // 根据由文章生成词频表countMap,生成哈夫曼编码表 + // key : 字符 + // value: 该字符编码后的二进制形式 + // 比如,频率表 A:60, B:45, C:13 D:69 E:14 F:5 G:3 + // A 10 + // B 01 + // C 0011 + // D 11 + // E 000 + // F 00101 + // G 00100 + public static HashMap huffmanForm(HashMap countMap) { + HashMap ans = new HashMap<>(); + if (countMap.size() == 1) { + for (char key : countMap.keySet()) { + ans.put(key, "0"); + } + return ans; + } + HashMap nodes = new HashMap<>(); + PriorityQueue heap = new PriorityQueue<>(new NodeComp()); + for (Entry entry : countMap.entrySet()) { + Node cur = new Node(entry.getValue()); + char cha = entry.getKey(); + nodes.put(cur, cha); + heap.add(cur); + } + while (heap.size() != 1) { + Node a = heap.poll(); + Node b = heap.poll(); + Node h = new Node(a.count + b.count); + h.left = a; + h.right = b; + heap.add(h); + } + Node head = heap.poll(); + fillForm(head, "", nodes, ans); + return ans; + } + + public static void fillForm(Node head, String pre, HashMap nodes, HashMap ans) { + if (nodes.containsKey(head)) { + ans.put(nodes.get(head), pre); + } else { + fillForm(head.left, pre + "0", nodes, ans); + fillForm(head.right, pre + "1", nodes, ans); + } + } + + // 原始字符串str,根据哈夫曼编码表,转译成哈夫曼编码返回 + public static String huffmanEncode(String str, HashMap huffmanForm) { + char[] s = str.toCharArray(); + StringBuilder builder = new StringBuilder(); + for (char cha : s) { + builder.append(huffmanForm.get(cha)); + } + return builder.toString(); + } + + // 原始字符串的哈夫曼编码huffmanEncode,根据哈夫曼编码表,还原成原始字符串 + public static String huffmanDecode(String huffmanEncode, HashMap huffmanForm) { + TrieNode root = createTrie(huffmanForm); + TrieNode cur = root; + char[] encode = huffmanEncode.toCharArray(); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < encode.length; i++) { + int index = encode[i] == '0' ? 0 : 1; + cur = cur.nexts[index]; + if (cur.nexts[0] == null && cur.nexts[1] == null) { + builder.append(cur.value); + cur = root; + } + } + return builder.toString(); + } + + public static TrieNode createTrie(HashMap huffmanForm) { + TrieNode root = new TrieNode(); + for (char key : huffmanForm.keySet()) { + char[] path = huffmanForm.get(key).toCharArray(); + TrieNode cur = root; + for (int i = 0; i < path.length; i++) { + int index = path[i] == '0' ? 0 : 1; + if (cur.nexts[index] == null) { + cur.nexts[index] = new TrieNode(); + } + cur = cur.nexts[index]; + } + cur.value = key; + } + return root; + } + + public static class TrieNode { + public char value; + public TrieNode[] nexts; + + public TrieNode() { + value = 0; + nexts = new TrieNode[2]; + } + } + + // 为了测试 + public static String randomNumberString(int len, int range) { + char[] str = new char[len]; + for (int i = 0; i < len; i++) { + str[i] = (char) ((int) (Math.random() * range) + 'a'); + } + return String.valueOf(str); + } + + // 为了测试 + public static void main(String[] args) { + // 根据词频表生成哈夫曼编码表 + HashMap map = new HashMap<>(); + map.put('A', 60); + map.put('B', 45); + map.put('C', 13); + map.put('D', 69); + map.put('E', 14); + map.put('F', 5); + map.put('G', 3); + HashMap huffmanForm = huffmanForm(map); + for (Entry entry : huffmanForm.entrySet()) { + System.out.println(entry.getKey() + " : " + entry.getValue()); + } + System.out.println("===================="); + // str是原始字符串 + String str = "CBBBAABBACAABDDEFBA"; + System.out.println(str); + // countMap是根据str建立的词频表 + HashMap countMap = countMap(str); + // hf是根据countMap生成的哈夫曼编码表 + HashMap hf = huffmanForm(countMap); + // huffmanEncode是原始字符串转译后的哈夫曼编码 + String huffmanEncode = huffmanEncode(str, hf); + System.out.println(huffmanEncode); + // huffmanDecode是哈夫曼编码还原成的原始字符串 + String huffmanDecode = huffmanDecode(huffmanEncode, hf); + System.out.println(huffmanDecode); + System.out.println("===================="); + System.out.println("大样本随机测试开始"); + // 字符串最大长度 + int len = 500; + // 所含字符种类 + int range = 26; + // 随机测试进行的次数 + int testTime = 100000; + for (int i = 0; i < testTime; i++) { + int N = (int) (Math.random() * len) + 1; + String test = randomNumberString(N, range); + HashMap counts = countMap(test); + HashMap form = huffmanForm(counts); + String encode = huffmanEncode(test, form); + String decode = huffmanDecode(encode, form); + if (!test.equals(decode)) { + System.out.println(test); + System.out.println(encode); + System.out.println(decode); + System.out.println("出错了!"); + } + } + System.out.println("大样本随机测试结束"); + } + +}