2. Question: select the maximum K number from a number of unordered numbers.
Solution 5,
Ideas:
1. using the fast grouping idea, we first take a random number in the unordered number and divide the unordered number into two parts: 1 and 2, where 1st is smaller than the random number set, part 1 is greater than the random number set;
2. If the number of exactly 1st parts (plus the random number) is K, the first K number is directly returned. If the number of 1st parts is greater than K, recursive queries the maximum number of K in Part 1. If the number of Part 2 is smaller than K, recursive queries the maximum number of K-length in Part 1, and the length is the number of Part 3;
The time complexity of this algorithm is O (n * log n). Like fast sorting, This sorting algorithm depends on the selection of random numbers, which is unstable.
Computing:
1. Split the entire array (simply take the first number as the split random number );
2. If the number of part 1 is K-1 after segmentation, the number of the first K of the array is required. After segmentation, the number of part 2 is smaller than K-1, the maximum number of K-split values in part 1 is recursively searched. If Part 1 is greater than K-1 after segmentation, the maximum number of K values in part 1 is recursively searched;
Code:
private int partition(int[] arr, int begin, int end) { int key = begin, tmp; for(int low = begin, high = end; low < high; ) { if(arr[low] < arr[high]) { tmp = arr[low]; //swap arr[low] and arr[high] arr[low] = arr[high]; arr[high] = tmp; if(key == low) { low++; key = high; } else { high--; key = low; } } else { if(key == low) { high--; } else { low++; } } } return key; } public void topK4(int []arr, int begin, int end, int k) { int split = partition(arr, begin, end); if((split - begin + 1) == k) { return; } else if(split - begin + 1 < k) { topK4(arr, split + 1, end, k - (split - begin) - 1); } else { topK4(arr, 0, split - 1, k); } }
Train of Thought: using the multi-channel merge idea, first divide the unordered number into M equal points, and sort the numbers in each equal point (you can simply use quick sorting, the time complexity is Q * log Q, where Q is the number of numbers in each shard), and then uses the loser tree for Merge Sorting, extract the maximum number from each equals value as the leaf node for merging and sorting, and compare the node with the parent node. The loser stays on the parent node, and the winner can continue to perform higher-level comparison;
Computing:
1. Divide the unordered number by M;
2. Extract the largest number of scores in sequence, and use them as the leaf node of the loser for sift up. output the winner node and replace the current maximum number with winner from the same score of the winner node, until the number of output winner nodes is K;
public class LoseTree { private int[] branches; private int[] nodes; public void getNumFromBuffer(List<Integer> buffer, int bufferIndex) throws Exception { //get number if(buffer.size() == 0) { throw new Exception("the buffer is null"); } branches[bufferIndex] = buffer.remove(0); } public int competitionBranch(int branchIndex) { int father = (nodes.length + branchIndex - 1) / 2; while(father >= 0) { if(branches[nodes[father]] > branches[branchIndex]) { //swap the nodes[father] and the branchIndex int tmp = nodes[father]; nodes[father] = branchIndex; branchIndex = tmp; } if(father == 0) break; else father = (father - 1) / 2; } return branchIndex; } public int getBranch(int branchIndex) { return branches[branchIndex]; } public int init(List<Integer>[] buffers) throws Exception { branches = new int[buffers.length]; for(int i = 0; i < branches.length; i++) { getNumFromBuffer(buffers[i], i); } nodes = new int[branches.length - 1]; int max = -1; for(int i = 0; i < branches.length; i++) { if(max < branches[i]) { max = i; } } for(int i = 0; i < nodes.length; i++) { nodes[i] = max; } int winnerIndex = 0; for(int i = 0; i < nodes.length; i++) { winnerIndex = competitionBranch(i); } return winnerIndex; } public LoseTree() { } } @SuppressWarnings({ "unchecked", "rawtypes"}) public List<Integer>[] createBuffer(int[] arr, int k) { List[] buffers = arr.length % k == 0 ? new List[arr.length / k] : new List[arr.length / k + 1]; for(int i = 0; i < buffers.length; i++) { buffers[i] = new ArrayList(); } for(int i = 0; i < arr.length; i++) { buffers[i / k].add(arr[i]); } int addition = arr.length % k; if(addition != 0) { int end = arr.length / k; for(int i = addition; i < k; i++) { buffers[end].add(0); } } for(int i = 0; i < buffers.length; i++) { Collections.sort(buffers[i], Collections.reverseOrder()); } return buffers; } public List<Integer> topK(int []arr, int k) throws Exception { List<Integer>[] buffers = createBuffer(arr, k); if(buffers.length == 1) { return buffers[0]; } LoseTree loseTree = new LoseTree(); int winnerIndex = loseTree.init(buffers); List<Integer> topKArr = new ArrayList<Integer>(); for(int i = 0; i < k - 1; i++) { winnerIndex = loseTree.competitionBranch(winnerIndex); topKArr.add(loseTree.getBranch(winnerIndex)); loseTree.getNumFromBuffer(buffers[winnerIndex], winnerIndex); } winnerIndex = loseTree.competitionBranch(winnerIndex); topKArr.add(loseTree.getBranch(winnerIndex)); return topKArr; }