zoukankan      html  css  js  c++  java
  • 数据结构与算法——前缀树和贪心算法(1)

    介绍前缀树

    何为前缀树?如何生成前缀树?

    例子:一个字符串类型的数组arrl,另一个字符串类型的数组arr2。arr2中有哪些字符,是arr 1中 出现的?请打印。arr2中有哪些字符,是作为arr 1中某个字符串前缀出现的?请打印。arr2 中有哪些字符,是作为arr1中某个字符串前缀出现的?请打印arr2中出现次数最大的前缀。

    public class TrieTree {
    
    	public static class TrieNode {
    		public int path;
    		public int end;
    		public TrieNode[] nexts;
    
    		public TrieNode() {
    			path = 0;
    			end = 0;
    			nexts = new TrieNode[26];
    		}
    	}
    
    	public static class Trie {
    		private TrieNode root;
    
    		public Trie() {
    			root = new TrieNode();
    		}
    
    		public void insert(String word) {
    			if (word == null) {
    				return;
    			}
    			char[] chs = word.toCharArray();
    			TrieNode node = root;
    			int index = 0;
    			for (int i = 0; i < chs.length; i++) {
    				index = chs[i] - 'a';
    				if (node.nexts[index] == null) {
    					node.nexts[index] = new TrieNode();
    				}
    				node = node.nexts[index];
    				node.path++;
    			}
    			node.end++;
    		}
    
    		public void delete(String word) {
    			if (search(word) != 0) {  //确定树中确定加入过word,才删除
    				char[] chs = word.toCharArray();
    				TrieNode node = root;
    				int index = 0;
    				for (int i = 0; i < chs.length; i++) {
    					index = chs[i] - 'a';
    					if (--node.nexts[index].path == 0) {  //C++要遍历到底去析构
    						node.nexts[index] = null;
    						return;
    					}
    					node = node.nexts[index];
    				}
    				node.end--;
    			}
    		}
    
    		public int search(String word) {  //word这个单词之前加入过几次
    			if (word == null) {
    				return 0;
    			}
    			char[] chs = word.toCharArray();
    			TrieNode 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 prefixNumber(String pre) {
    			if (pre == null) {
    				return 0;
    			}
    			char[] chs = pre.toCharArray();
    			TrieNode 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.path;
    		}
    	}
    
    	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"));
    	}
    }
    

    贪心算法

    在某一个标准下,优先考虑最满足标准的样本,最后考虑最不满足标准的样本,最终得到 一个答案的算法,叫作贪心算法。也就是说,不从整体最优上加以考虑,所做出的是在某种意义上的局部最优解。

    局部最优-?->整体最优

    贪心算法的在笔试时的解题套路

    1, 实现一个不依靠贪心策略的解法X,可以用最暴力的尝试

    2, 脑补出贪心策略A、贪心策略B、贪心策略C...

    3, 用解法X和对数器,去验证每一个贪心策略,用实验的方式得知哪个贪心策略正确

    4,不要去纠结贪心策略的证明

    从头到尾展示最正统的贪心策略求解过程

    例子:给定一个字符串类型的数组strs,找到一种拼接方式,使得把所有字符串拼起来之后形成的 字符串具有最小的字典序。证明贪心策略可能是件非常腌心的事情。平时当然推荐你搞清楚所有的来龙去脉,但是笔试 时用对数器的方式!

    比较策略,要有传递性

    import java.util.Arrays;
    import java.util.Comparator;
    
    public class LowestLexicography {
    
    	public static class MyComparator implements Comparator<String> {
    		@Override
    		public int compare(String a, String b) {
    			return (a + b).compareTo(b + a);
    		}
    	}
    
    	public static String lowestString(String[] strs) {
    		if (strs == null || strs.length == 0) {
    			return "";
    		}
    		Arrays.sort(strs, new MyComparator());
    		String res = "";
    		for (int i = 0; i < strs.length; i++) {
                res += strs[i];
    		}
    		return res;
    	}
    
    	public static void main(String[] args) {
    		String[] strs1 = { "jibw", "ji", "jp", "bw", "jibw" };
    		System.out.println(lowestString(strs1));
    		String[] strs2 = { "ba", "b" };
    }
    

    贪心策略在实现时,经常使用到的技巧:

    1, 根据某标准建立一个比较器来排序

    2, 根据某标准建立一个比较器来组成堆

    一块金条切成两半,是需要花费和长度数值一样的铜板的。比如长度为20的金 条,不管切成长度多大的两半,都要花费20个铜板。一群人想整分整块金条,怎么分最省铜板?

    例如,给定数组{10,20,30},代表一共三个人,整块金条长度为10+20+30=60。金条要分成10,20,30三个部分。如果先把长度60的金条分成10和50,花费60; 再把长度50的金条分成20和30,花费50; 一共花费110铜板。但是如果先把长度60的金条分成30和30,花费60;再把长度30金条分成10和20, 花费30; 一共花费90铜板。输入一个数组,返回分割的最小代价。

    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    public class LessMoneySplitGold {
    
    	public static int lessMoney(int[] arr) {
    		PriorityQueue<Integer> pQ = new PriorityQueue<>();
    		for (int i = 0; i < arr.length; i++) {
    			pQ.add(arr[i]);
    		}
    		int sum = 0;
    		int cur = 0;
    		while (pQ.size() > 1) {
    			cur = pQ.poll() + pQ.poll();
    			sum += cur;
    			pQ.add(cur);
    		}
    		return sum;
    	}
    
    	public static class MinheapComparator implements Comparator<Integer> {
    
    		@Override
    		public int compare(Integer o1, Integer o2) {
    			return o1 - o2; // < 0  o1 < o2  负数
    		}
    
    	}
    
    	public static class MaxheapComparator implements Comparator<Integer> {
    
    		@Override
    		public int compare(Integer o1, Integer o2) {
    			return o2 - o1; // <   o2 < o1
    		}
    
    	}
    
    	public static void main(String[] args) {
    		// solution
    		int[] arr = { 6, 7, 8, 9 };
    		System.out.println(lessMoney(arr));
    		int[] arrForHeap = { 3, 5, 2, 7, 0, 1, 6, 4 };
    		// min heap
    		PriorityQueue<Integer> minQ1 = new PriorityQueue<>();
    		for (int i = 0; i < arrForHeap.length; i++) {
    			minQ1.add(arrForHeap[i]);
    		}
    		while (!minQ1.isEmpty()) {
    			System.out.print(minQ1.poll() + " ");
    		}
    		System.out.println();
    		// min heap use Comparator
    		PriorityQueue<Integer> minQ2 = new PriorityQueue<>(new MinheapComparator());
    		for (int i = 0; i < arrForHeap.length; i++) {
    			minQ2.add(arrForHeap[i]);
    		}
    		while (!minQ2.isEmpty()) {
    			System.out.print(minQ2.poll() + " ");
    		}
    		System.out.println();
    		// max heap use Comparator
    		PriorityQueue<Integer> maxQ = new PriorityQueue<>(new MaxheapComparator());
    		for (int i = 0; i < arrForHeap.length; i++) {
    			maxQ.add(arrForHeap[i]);
    		}
    		while (!maxQ.isEmpty()) {
    			System.out.print(maxQ.poll() + " ");
    		}
    	}
    }
    

    一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。 给你每一个项目开始的时间和结束的时间(给你一个数组,里面是一个个具体 的项目),你来安排宣讲的日程,要求会议室进行的宣讲的场次最多。返回这个最多的宣讲场次。

    import java.util.Arrays;
    import java.util.Comparator;
    
    	public static class Program {
    		public int start;
    		public int end;
    
    		public Program(int start, int end) {
    			this.start = start;
    			this.end = end;
    		}
    	}
    
    	public static class ProgramComparator implements Comparator<Program> { //比较器
    
    		@Override
    		public int compare(Program o1, Program o2) {
    			return o1.end - o2.end;
    		}
    	}
    
    	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;
    	}
    	public static void main(String[] args) {
    	}
    }
    

    输入:正数数组costs 正数数组profits 正数k 正数m

    含义:costs [i]表示i号项目的花费 profits [i]表示i号项目在扣除花费之后还能挣到的钱(利润)

    k表示你只能串行的最多做k个项目 m表示你初始的资金

    说明:你每做完一个项目,马上获得的收益,可以支持你去做下一个项目。

    输出:你最后获得的最大钱数。

    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    public class IPO {
    	public static class Node {
    		public int p;
    		public int c;
    
    		public Node(int p, int c) {
    			this.p = p;
    			this.c = c;
    		}
    	}
    
    	public static class MinCostComparator implements Comparator<Node> {
    
    		@Override
    		public int compare(Node o1, Node o2) {
    			return o1.c - o2.c;
    		}
    	}
    
    	public static class MaxProfitComparator implements Comparator<Node> {
    
    		@Override
    		public int compare(Node o1, Node o2) {
    			return o2.p - o1.p;
    		}
    	}
    
    	public static int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) {
    		Node[] nodes = new Node[Profits.length];
    		for (int i = 0; i < Profits.length; i++) {
    			nodes[i] = new Node(Profits[i], Capital[i]);
    		}
    		PriorityQueue<Node> minCostQ = new PriorityQueue<>(new MinCostComparator());
    		PriorityQueue<Node> maxProfitQ = new PriorityQueue<>(new MaxProfitComparator());
    		for (int i = 0; i < nodes.length; i++) {
    			minCostQ.add(nodes[i]);
    		}
    		for (int i = 0; i < k; i++) {
    			while (!minCostQ.isEmpty() && minCostQ.peek().c <= W) {
    				maxProfitQ.add(minCostQ.poll());
    			}
    			if (maxProfitQ.isEmpty()) {
    				return W;
    			}
    			W += maxProfitQ.poll().p;
    		}
    		return W;
    	}
    }
    

    一个数据流中,随时可以取得中位数

    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    public class MadianQuick {
    
    	public static class MedianHolder {
    		private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new MaxHeapComparator());
    		private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(new MinHeapComparator());
    
    		private void modifyTwoHeapsSize() {
    			if (this.maxHeap.size() == this.minHeap.size() + 2) {
    				this.minHeap.add(this.maxHeap.poll());
    			}
    			if (this.minHeap.size() == this.maxHeap.size() + 2) {
    				this.maxHeap.add(this.minHeap.poll());
    			}
    		}
    
    		public void addNumber(int num) {
    			if (maxHeap.isEmpty() || num <= maxHeap.peek()) {
    				maxHeap.add(num);
    			} else {
    				minHeap.add(num);
    			}
    			modifyTwoHeapsSize();
    		}
    
    		public Integer getMedian() {
    			int maxHeapSize = this.maxHeap.size();
    			int minHeapSize = this.minHeap.size();
    			if (maxHeapSize + minHeapSize == 0) {
    				return null;
    			}
    			Integer maxHeapHead = this.maxHeap.peek();
    			Integer minHeapHead = this.minHeap.peek();
    			if (((maxHeapSize + minHeapSize) & 1) == 0) {
    				return (maxHeapHead + minHeapHead) / 2;
    			}
    			return maxHeapSize > minHeapSize ? maxHeapHead : minHeapHead;
    		}
    
    	}
    
    	public static class MaxHeapComparator implements Comparator<Integer> {
    		@Override
    		public int compare(Integer o1, Integer o2) {
    			if (o2 > o1) {
    				return 1;
    			} else {
    				return -1;
    			}
    		}
    	}
    
    	public static class MinHeapComparator implements Comparator<Integer> {
    		@Override
    		public int compare(Integer o1, Integer o2) {
    			if (o2 < o1) {
    				return 1;
    			} else {
    				return -1;
    			}
    		}
    	}
    
    	// for test
    	public static int[] getRandomArray(int maxLen, int maxValue) {
    		int[] res = new int[(int) (Math.random() * maxLen) + 1];
    		for (int i = 0; i != res.length; i++) {
    			res[i] = (int) (Math.random() * maxValue);
    		}
    		return res;
    	}
    
    	// for test, this method is ineffective but absolutely right
    	public static int getMedianOfArray(int[] arr) {
    		int[] newArr = Arrays.copyOf(arr, arr.length);
    		Arrays.sort(newArr);
    		int mid = (newArr.length - 1) / 2;
    		if ((newArr.length & 1) == 0) {
    			return (newArr[mid] + newArr[mid + 1]) / 2;
    		} else {
    			return newArr[mid];
    		}
    	}
    
    	public static void printArray(int[] arr) {
    		for (int i = 0; i != arr.length; i++) {
    			System.out.print(arr[i] + " ");
    		}
    		System.out.println();
    	}
    
    	public static void main(String[] args) {
    		boolean err = false;
    		int testTimes = 200000;
    		for (int i = 0; i != testTimes; i++) {
    			int len = 30;
    			int maxValue = 1000;
    			int[] arr = getRandomArray(len, maxValue);
    			MedianHolder medianHold = new MedianHolder();
    			for (int j = 0; j != arr.length; j++) {
    				medianHold.addNumber(arr[j]);
    			}
    			if (medianHold.getMedian() != getMedianOfArray(arr)) {
    				err = true;
    				printArray(arr);
    				break;
    			}
    		}
    		System.out.println(err ? "Oops" : "beautiful ^_^");
    	}
    }
    
  • 相关阅读:
    递归 深拷贝
    js 基础复习(0)
    js数组冒泡排序,快速排序的原理以及实现
    .sass 和 .scss 区别
    ionic2-从搭建环境说起
    Unity3d截图保存到Android相册的实现
    总是要总结一年的工作(写给自己和想要从技术创业开公司的朋友们)
    初入职场(插曲-如何更称职的工作)
    初入职场(插曲-你的成长代价)
    初入职场(面试)
  • 原文地址:https://www.cnblogs.com/wwj99/p/12230745.html
Copyright © 2011-2022 走看看