算法入门基础——前缀数、最小字典序问题、切金条问题、会议室安排问题、项目收益问题、随机中位数问题
package com.zuoshen.jichurumen.class07; import java.util.Arrays; import java.util.Comparator; import java.util.PriorityQueue; /** * @author ShiZhe * @create 2022-03-08 23:14 */ public class code01 { /** * 前缀数节点结构 */ public static class TrieNode { // 通过次数 public int pass; // 作为结尾节点的次数 public int end; // 可能包涵的节点数组 public TrieNode[] nexts; public TrieNode() { pass = 0; end = 0; // 题目是26个字母的小写 nexts = new TrieNode[26]; } } /** * 前缀树 */ public static class Trie { // 头结点 public TrieNode root; // 初始化 public Trie() { root = new TrieNode(); } // 字符串插入 public void insert(String word) { if (word == null) { return; } // 将字符串转为字符数组 char[] chars = word.toCharArray(); // 将前缀树根节点赋值给node TrieNode node = root; // 节点数组的下标 int index = 0; // 循环 for (int i = 0; i < chars.length; i++) { index = chars[i] - 'a'; if (node.nexts[index] == null) { node.nexts[index] = new TrieNode(); } node = node.nexts[index]; node.pass++; } node.end++; } // 查看某字符串是否存在,存在返回字符串插入次数即end public int search(String word) { if (word == null) { return 0; } char[] chars = word.toCharArray(); TrieNode node = root; int index = 0; for (int i = 0; i < chars.length; i++) { index = chars[i] - 'a'; if (node.nexts[index] == null) { return 0; } node = node.nexts[index]; } return node.end; } // 删除某字符串 public void delete(String word) { if (search(word) != 0) { char[] chars = word.toCharArray(); TrieNode node = root; int index = 0; for (int i = 0; i < chars.length; i++) { index = chars[i] - 'a'; // 当该路径只有该字符串时,后面不需要遍历,直接删除 if (--node.nexts[index].pass == 0) { node.nexts[index] = null; return; } node = node.nexts[i]; } node.end--; } } // 查找以某字符串为前缀的数量 public int prefixNumber(String pre) { if (pre == null) { return 0; } char[] chars = pre.toCharArray(); TrieNode node = root; int index = 0; for (int i = 0; i < chars.length; i++) { index = chars[i] - 'a'; if (node.nexts[index] == null) { return 0; } node = node.nexts[index]; } return node.pass; } } /** * 字符串拼接的最小字典序问题——贪心 * 字典序:字符串在字典中的位置 * @param strings * @return */ public static String lowestString(String[] strings) { if (strings == null || strings.length == 0) { return ""; } Arrays.sort(strings, new MyComparator()); String result = ""; for (int i = 0; i < strings.length; i++) { result += strings[i]; } return result; } /** * 字符串拼接问题的比较器 */ public static class MyComparator implements Comparator<String> { @Override public int compare(String o1, String o2) { return (o1 + o2).compareTo(o2 + o1); } } /** * 切金条问题 * 哈弗曼编码 * @param arr * @return */ public static int lessMoney(int[] arr) { PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(); for (int i = 0; i < arr.length; i++) { priorityQueue.add(arr[i]); } int sum = 0; int cur; while (priorityQueue.size() > 1) { cur = priorityQueue.poll() + priorityQueue.poll(); sum += cur; priorityQueue.add(cur); } return sum; } /** * 会议室安排问题的项目结构 */ public static class Program { // 开始时间 public int start; // 结束时间 public int end; // 构造函数 public Program(int start, int end) { this.start = start; this.end = end; } } /** * 会议室安排——贪心 * 按照结束时间排序,持续时间越短,安排越多 * @param programs * @param start * @return */ public static int bestArrange(Program[] programs, int start) { Arrays.sort(programs, new ProgramComparator()); int result = 0; for (int i = 0; i < programs.length; i++) { if (start <= programs[i].start) { result++; start = programs[i].end; } } return result; } /** * 会议室安排问题定义的比较器,按照end排列 */ public static class ProgramComparator implements Comparator<Program> { @Override public int compare(Program o1, Program o2) { return o1.end - o2.end; } } /** * IPO对应的节点结构 */ public static class CostNode { // 花费 public int cost; // 利润 public int profit; // 构造函数 public CostNode(int cost, int profit) { this.cost = cost; this.profit = profit; } } /** * 每做完一个项目,马上获得的收益,可以支持你去做下一个项目 * @param costs 表示i号项目的花费 * @param profits 表示i号项目在扣除花费之后还能挣到的钱(利润) * @param k 表示你只能串行的最多做k个项目 * @param m 表示你初始的资金 * @return 最后获得的最大钱数 */ public static int findMaximizedCapital(int[] costs, int[] profits, int k, int m) { // 节点初始化 CostNode[] costNodes = new CostNode[costs.length]; // 节点填充数据 for (int i = 0; i < costs.length; i++) { costNodes[i] = new CostNode(costs[i], profits[i]); } // 项目的cost小根堆 PriorityQueue<CostNode> minCostQueue = new PriorityQueue<>(new MinCostComparator()); // 可进行项目的profit大根堆 PriorityQueue<CostNode> maxProfitQueue = new PriorityQueue<>(new MaxProfitComparator()); // 小根堆初始化 for (int i = 0; i < costNodes.length; i++) { minCostQueue.add(costNodes[i]); } // k个项目限制 for (int i = 0; i < k; i++) { // peek()获取堆顶元素但是不弹出 while (!minCostQueue.isEmpty() && minCostQueue.peek().cost <= m) { maxProfitQueue.add(minCostQueue.poll()); } // 无满足当前资金的花费的项目 if (maxProfitQueue.isEmpty()) { return m; } // 利润叠加 m += maxProfitQueue.poll().profit; } return m; } /** * cost从小到大排序 */ public static class MinCostComparator implements Comparator<CostNode> { @Override public int compare(CostNode o1, CostNode o2) { return o1.cost - o2.cost; } } /** * profit从大到小排序 */ public static class MaxProfitComparator implements Comparator<CostNode> { @Override public int compare(CostNode o1, CostNode o2) { return o2.profit - o1.profit; } } /** * 一个数据流中,随时可以取得中位数 * 2个堆,一个从小到大,一个从大到小 */ public static class MedianHolder { // 小根堆保存的是大值 private PriorityQueue<Integer> minQueue = new PriorityQueue<>(new MinHeapComparator()); // 大根堆保存的是小值 private PriorityQueue<Integer> maxQueue = new PriorityQueue<>(new MaxHeapComparator()); // 调整,保证2个堆的size差不大于2 private void modifyTwoHeapsSize() { if (this.minQueue.size() == this.maxQueue.size() + 2) { this.maxQueue.add(this.minQueue.poll()); } if (this.maxQueue.size() == this.minQueue.size() + 2) { this.minQueue.add(this.maxQueue.poll()); } } // 添加数 private void addNumber(int num) { if (maxQueue.isEmpty() || num <= maxQueue.peek()) { maxQueue.add(num); } else { minQueue.add(num); } modifyTwoHeapsSize(); } // 获取中位数 public Integer getMedian() { int maxSize = this.maxQueue.size(); int minSize = this.minQueue.size(); // 无数 if (maxSize + minSize == 0) { return null; } Integer maxHead = this.maxQueue.peek(); Integer minHead = this.minQueue.peek(); // 总数为偶数,中位数是中间2个数之和的一半 // 条件为maxSize == minSize也行 if (((maxSize + minSize) & 1) == 0) { return (maxHead + minHead) / 2; } return maxSize > minSize ? maxHead :minHead; } } /** * 小根堆 */ public static class MinHeapComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } } /** * 大根堆 */ public static class MaxHeapComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { return o2 -o1; } } public static void main(String[] args) { // 前缀树 Trie trie = new Trie(); System.out.println(trie.search("zuo")); trie.insert("zuo"); System.out.println(trie.search("zuo")); trie.delete("zuo"); System.out.println(trie.search("zuo")); trie.insert("zuo"); trie.insert("zuo"); trie.delete("zuo"); System.out.println(trie.search("zuo")); trie.delete("zuo"); System.out.println(trie.search("zuo")); trie.insert("zuoa"); trie.insert("zuoac"); trie.insert("zuoab"); trie.insert("zuoad"); trie.delete("zuoa"); System.out.println(trie.search("zuoa")); System.out.println(trie.prefixNumber("zuo")); // 字符串拼接最小字典序 String[] strs1 = { "jibw", "ji", "jp", "bw", "jibw" }; System.out.println(lowestString(strs1)); String[] strs2 = { "ba", "b" }; System.out.println(lowestString(strs2)); // 切金条问题 int[] arr = { 6, 7, 8, 9 }; System.out.println(lessMoney(arr)); } }