From 5873ab2c0a8f6979a59d47ddde8c5bc9072f6645 Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Thu, 23 Mar 2023 18:04:06 +0800 Subject: [PATCH] modify code --- .../第03期/mca_08/Code01_Trie.java | 102 ++++++++++++++++ .../第03期/mca_08/Code02_Trie.java | 104 ++++++++++++++++ .../mca_08/Code03_PrefixAndSuffixSearch.java | 111 ++++++++++++++++++ .../第03期/mca_08/Code04_SameTeams.java | 62 ++++++++++ .../Code05_MaximumFrequencyStack.java | 2 +- .../Code06_InsertDeleteGetRandom.java | 2 +- .../mca_08/Code07_ExpressionCompute.java | 57 +++++++++ 7 files changed, 438 insertions(+), 2 deletions(-) create mode 100644 MCA算法突击课/第03期/mca_08/Code01_Trie.java create mode 100644 MCA算法突击课/第03期/mca_08/Code02_Trie.java create mode 100644 MCA算法突击课/第03期/mca_08/Code03_PrefixAndSuffixSearch.java create mode 100644 MCA算法突击课/第03期/mca_08/Code04_SameTeams.java rename MCA算法突击课/第03期/{mca_07 => mca_08}/Code05_MaximumFrequencyStack.java (98%) rename MCA算法突击课/第03期/{mca_07 => mca_08}/Code06_InsertDeleteGetRandom.java (98%) create mode 100644 MCA算法突击课/第03期/mca_08/Code07_ExpressionCompute.java diff --git a/MCA算法突击课/第03期/mca_08/Code01_Trie.java b/MCA算法突击课/第03期/mca_08/Code01_Trie.java new file mode 100644 index 0000000..70bb809 --- /dev/null +++ b/MCA算法突击课/第03期/mca_08/Code01_Trie.java @@ -0,0 +1,102 @@ +package 第03期.mca_08; + +public class Code01_Trie { + + // 测试链接 : https://leetcode.cn/problems/implement-trie-ii-prefix-tree/ + // 提交Trie类可以直接通过 + // 原来代码是对的,但是既然找到了直接测试的链接,那就直接测吧 + // 这个链接上要求实现的功能和课上讲的完全一样 + // 该前缀树的路用数组实现 + class Trie { + + class Node { + public int pass; + public int end; + public Node[] nexts; + + public Node() { + pass = 0; + end = 0; + nexts = new Node[26]; + } + } + + private Node root; + + public Trie() { + root = new Node(); + } + + public void insert(String word) { + if (word == null) { + return; + } + char[] str = word.toCharArray(); + Node node = root; + node.pass++; + int path = 0; + for (int i = 0; i < str.length; i++) { // 从左往右遍历字符 + path = str[i] - 'a'; // 由字符,对应成走向哪条路 + if (node.nexts[path] == null) { + node.nexts[path] = new Node(); + } + node = node.nexts[path]; + node.pass++; + } + node.end++; + } + + public void erase(String word) { + if (countWordsEqualTo(word) != 0) { + char[] chs = word.toCharArray(); + Node node = root; + node.pass--; + int path = 0; + for (int i = 0; i < chs.length; i++) { + path = chs[i] - 'a'; + if (--node.nexts[path].pass == 0) { + node.nexts[path] = null; + return; + } + node = node.nexts[path]; + } + node.end--; + } + } + + public int countWordsEqualTo(String word) { + if (word == null) { + return 0; + } + char[] chs = word.toCharArray(); + Node node = root; + int index = 0; + for (int i = 0; i < chs.length; i++) { + index = chs[i] - 'a'; + if (node.nexts[index] == null) { + return 0; + } + node = node.nexts[index]; + } + return node.end; + } + + public int countWordsStartingWith(String pre) { + if (pre == null) { + return 0; + } + char[] chs = pre.toCharArray(); + Node node = root; + int index = 0; + for (int i = 0; i < chs.length; i++) { + index = chs[i] - 'a'; + if (node.nexts[index] == null) { + return 0; + } + node = node.nexts[index]; + } + return node.pass; + } + } + +} diff --git a/MCA算法突击课/第03期/mca_08/Code02_Trie.java b/MCA算法突击课/第03期/mca_08/Code02_Trie.java new file mode 100644 index 0000000..47da77a --- /dev/null +++ b/MCA算法突击课/第03期/mca_08/Code02_Trie.java @@ -0,0 +1,104 @@ +package 第03期.mca_08; + +import java.util.HashMap; + +public class Code02_Trie { + + // 测试链接 : https://leetcode.cn/problems/implement-trie-ii-prefix-tree/ + // 提交Trie类可以直接通过 + // 原来代码是对的,但是既然找到了直接测试的链接,那就直接测吧 + // 这个链接上要求实现的功能和课上讲的完全一样 + // 该前缀树的路用哈希表实现 + class Trie { + + class Node { + public int pass; + public int end; + public HashMap nexts; + + public Node() { + pass = 0; + end = 0; + nexts = new HashMap<>(); + } + } + + private Node root; + + public Trie() { + root = new Node(); + } + + public void insert(String word) { + if (word == null) { + return; + } + char[] chs = word.toCharArray(); + Node node = root; + node.pass++; + int index = 0; + for (int i = 0; i < chs.length; i++) { + index = (int) chs[i]; + if (!node.nexts.containsKey(index)) { + node.nexts.put(index, new Node()); + } + node = node.nexts.get(index); + node.pass++; + } + node.end++; + } + + public void erase(String word) { + if (countWordsEqualTo(word) != 0) { + char[] chs = word.toCharArray(); + Node node = root; + node.pass--; + int index = 0; + for (int i = 0; i < chs.length; i++) { + index = (int) chs[i]; + if (--node.nexts.get(index).pass == 0) { + node.nexts.remove(index); + return; + } + node = node.nexts.get(index); + } + node.end--; + } + } + + public int countWordsEqualTo(String word) { + if (word == null) { + return 0; + } + char[] chs = word.toCharArray(); + Node node = root; + int index = 0; + for (int i = 0; i < chs.length; i++) { + index = (int) chs[i]; + if (!node.nexts.containsKey(index)) { + return 0; + } + node = node.nexts.get(index); + } + return node.end; + } + + public int countWordsStartingWith(String pre) { + if (pre == null) { + return 0; + } + char[] chs = pre.toCharArray(); + Node node = root; + int index = 0; + for (int i = 0; i < chs.length; i++) { + index = (int) chs[i]; + if (!node.nexts.containsKey(index)) { + return 0; + } + node = node.nexts.get(index); + } + return node.pass; + } + } + +} diff --git a/MCA算法突击课/第03期/mca_08/Code03_PrefixAndSuffixSearch.java b/MCA算法突击课/第03期/mca_08/Code03_PrefixAndSuffixSearch.java new file mode 100644 index 0000000..485f352 --- /dev/null +++ b/MCA算法突击课/第03期/mca_08/Code03_PrefixAndSuffixSearch.java @@ -0,0 +1,111 @@ +package 第03期.mca_08; + +import java.util.ArrayList; + +// 设计一个包含一些单词的特殊词典,并能够通过前缀和后缀来检索单词。 +// 实现 WordFilter 类: +// WordFilter(string[] words) 使用词典中的单词 words 初始化对象 +// f(string pref, string suff) +// 返回词典中具有前缀 prefix 和后缀 suff 的单词的下标 +// 如果存在不止一个满足要求的下标,返回其中 最大的下标 +// 如果不存在这样的单词,返回 -1 。 +// 测试链接 : https://leetcode.cn/problems/prefix-and-suffix-search/ +public class Code03_PrefixAndSuffixSearch { + + // 提交以下这个类 + class WordFilter { + + class TrieNode { + TrieNode[] nexts; + ArrayList indies; + + public TrieNode() { + nexts = new TrieNode[26]; + indies = new ArrayList<>(); + } + } + + TrieNode preHead; + + TrieNode sufHead; + + public WordFilter(String[] words) { + preHead = new TrieNode(); + sufHead = new TrieNode(); + for (int i = 0; i < words.length; i++) { + String word = words[i]; + TrieNode cur = preHead; + for (int j = 0; j < word.length(); j++) { + int path = word.charAt(j) - 'a'; + if (cur.nexts[path] == null) { + cur.nexts[path] = new TrieNode(); + } + cur = cur.nexts[path]; + cur.indies.add(i); + } + cur = sufHead; + for (int j = word.length() - 1; j >= 0; j--) { + int path = word.charAt(j) - 'a'; + if (cur.nexts[path] == null) { + cur.nexts[path] = new TrieNode(); + } + cur = cur.nexts[path]; + cur.indies.add(i); + } + } + } + + public int f(String pref, String suff) { + ArrayList preList = null; + TrieNode cur = preHead; + for (int i = 0; i < pref.length() && cur != null; i++) { + cur = cur.nexts[pref.charAt(i) - 'a']; + } + if (cur != null) { + preList = cur.indies; + } + if (preList == null) { + return -1; + } + ArrayList sufList = null; + cur = sufHead; + for (int i = suff.length() - 1; i >= 0 && cur != null; i--) { + cur = cur.nexts[suff.charAt(i) - 'a']; + } + if (cur != null) { + sufList = cur.indies; + } + if (sufList == null) { + return -1; + } + ArrayList small = preList.size() <= sufList.size() ? preList : sufList; + ArrayList big = small == preList ? sufList : preList; + for (int i = small.size() - 1; i >= 0; i--) { + if (bs(big, small.get(i))) { + return small.get(i); + } + } + return -1; + } + + private boolean bs(ArrayList sorted, int num) { + int l = 0; + int r = sorted.size() - 1; + int m = 0; + int midValue = 0; + while (l <= r) { + m = (l + r) / 2; + midValue = sorted.get(m); + if (midValue == num) { + return true; + } else if (midValue < num) { + l = m + 1; + } else { + r = m - 1; + } + } + return false; + } + } + +} diff --git a/MCA算法突击课/第03期/mca_08/Code04_SameTeams.java b/MCA算法突击课/第03期/mca_08/Code04_SameTeams.java new file mode 100644 index 0000000..763409a --- /dev/null +++ b/MCA算法突击课/第03期/mca_08/Code04_SameTeams.java @@ -0,0 +1,62 @@ +package 第03期.mca_08; + +import java.util.ArrayList; +import java.util.HashMap; + +// 来自字节飞书团队 +// 假设数组a和数组b为两组信号 +// 1) length(b) <= length(a) +// 2) 对于任意0<=i indices; + public HashMap nexts; + + public TrieNode() { + indices = new ArrayList<>(); + nexts = new HashMap<>(); + } + + } + + public static int[] sameTeamsArray(int[][] bs, int[][] as) { + int m = bs.length; + TrieNode root = new TrieNode(); + TrieNode cur = null; + for (int i = 0; i < m; i++) { + int k = bs[i].length; + cur = root; + for (int j = 1; j < k; j++) { + int diff = bs[i][j] - bs[i][j - 1]; + if (!cur.nexts.containsKey(diff)) { + cur.nexts.put(diff, new TrieNode()); + } + cur = cur.nexts.get(diff); + } + cur.indices.add(i); + } + int[] ans = new int[m]; + int n = as.length; + for (int i = 0; i < n; i++) { + int k = as[i].length; + cur = root; + for (int j = 1; j < k; j++) { + int diff = as[i][j] - as[i][j - 1]; + if (!cur.nexts.containsKey(diff)) { + break; + } + cur = cur.nexts.get(diff); + for (int index : cur.indices) { + ans[index]++; + } + } + } + return ans; + } + +} diff --git a/MCA算法突击课/第03期/mca_07/Code05_MaximumFrequencyStack.java b/MCA算法突击课/第03期/mca_08/Code05_MaximumFrequencyStack.java similarity index 98% rename from MCA算法突击课/第03期/mca_07/Code05_MaximumFrequencyStack.java rename to MCA算法突击课/第03期/mca_08/Code05_MaximumFrequencyStack.java index 11a703c..5cd1303 100644 --- a/MCA算法突击课/第03期/mca_07/Code05_MaximumFrequencyStack.java +++ b/MCA算法突击课/第03期/mca_08/Code05_MaximumFrequencyStack.java @@ -1,4 +1,4 @@ -package 第03期.mca_07; +package 第03期.mca_08; import java.util.ArrayList; import java.util.HashMap; diff --git a/MCA算法突击课/第03期/mca_07/Code06_InsertDeleteGetRandom.java b/MCA算法突击课/第03期/mca_08/Code06_InsertDeleteGetRandom.java similarity index 98% rename from MCA算法突击课/第03期/mca_07/Code06_InsertDeleteGetRandom.java rename to MCA算法突击课/第03期/mca_08/Code06_InsertDeleteGetRandom.java index 2684d7b..fe3e4c0 100644 --- a/MCA算法突击课/第03期/mca_07/Code06_InsertDeleteGetRandom.java +++ b/MCA算法突击课/第03期/mca_08/Code06_InsertDeleteGetRandom.java @@ -1,4 +1,4 @@ -package 第03期.mca_07; +package 第03期.mca_08; import java.util.HashMap; diff --git a/MCA算法突击课/第03期/mca_08/Code07_ExpressionCompute.java b/MCA算法突击课/第03期/mca_08/Code07_ExpressionCompute.java new file mode 100644 index 0000000..674f628 --- /dev/null +++ b/MCA算法突击课/第03期/mca_08/Code07_ExpressionCompute.java @@ -0,0 +1,57 @@ +package 第03期.mca_08; + +import java.util.LinkedList; + +// 本题测试链接 : https://leetcode.com/problems/basic-calculator-iii/ +public class Code07_ExpressionCompute { + + public static int calculate(String str) { + return f(str.toCharArray(), 0)[0]; + } + + // 请从str[i...]往下算,遇到字符串终止位置或者右括号,就停止 + // 返回两个值,长度为2的数组 + // 0) 负责的这一段的结果是多少 + // 1) 负责的这一段计算到了哪个位置 + public static int[] f(char[] str, int i) { + LinkedList queue = new LinkedList(); + int cur = 0; + int[] bra = null; + // 从i出发,开始撸串 + while (i < str.length && str[i] != ')') { + if (str[i] >= '0' && str[i] <= '9') { + cur = cur * 10 + str[i++] - '0'; + } else if (str[i] != '(') { // 遇到的是运算符号 + addNum(queue, cur, str[i++]); + cur = 0; + } else { // 遇到左括号了 + bra = f(str, i + 1); + cur = bra[0]; + i = bra[1] + 1; + } + } + addNum(queue, cur, '+'); + return new int[] { getAns(queue), i }; + } + + public static void addNum(LinkedList queue, int num, char op) { + if (!queue.isEmpty() && (queue.peekLast().equals("*") || queue.peekLast().equals("/"))) { + String top = queue.pollLast(); + int pre = Integer.valueOf(queue.pollLast()); + num = top.equals("*") ? (pre * num) : (pre / num); + } + queue.addLast(String.valueOf(num)); + queue.addLast(String.valueOf(op)); + } + + public static int getAns(LinkedList queue) { + int ans = Integer.valueOf(queue.pollFirst()); + while (queue.size() > 1) { + String op = queue.pollFirst(); + int num = Integer.valueOf(queue.pollFirst()); + ans += op.equals("+") ? num : -num; + } + return ans; + } + +}