輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。html
Java 中的PriorityQueue是一個基於優先級堆的無界優先級隊列。優先級隊列的元素按照其天然順序進行排序,或者根據構造隊列時提供的 Comparator 進行排序,具體取決於所使用的構造方法。優先級隊列不容許使用 null 元素。依靠天然順序的優先級隊列還不容許插入不可比較的對象(這樣作可能致使 ClassCastException)。java
此隊列的頭是按指定排序方式肯定的最小元素。若是多個元素都是最小值,則頭是其中一個元素——選擇方法是任意的。隊列獲取操做 poll、 remove、peek 和 element 訪問處於隊列頭的元素。ide
關於PriorityQueue的更多介紹能夠查看:https://blog.csdn.net/x_i_y_u_e/article/details/46381481。ui
關於採用PriorityQueue實現最大堆和最小堆,能夠參考:http://www.cnblogs.com/yongh/p/9945539.htmlspa
https://www.cnblogs.com/Elliott-Su-Faith-change-our-life/p/7472265.html.net
選擇最小的k個數能夠用冒泡排序,複雜度爲O(n*k),有點高。最經典的方法是使用最大堆,每次取數與堆頂的元素進行比較,若是堆頂元素大,則刪除堆頂元素,並添加這個新數到堆中。code
Java沒有堆的實現,現場寫也來不及,有的文獻說用TreeSet,好比劍指offer,可是TreeSet是一個set,相同的數只能存一個,相比之下,Java中的PriorityQueue卻是一個不錯的選擇。htm
經過PriorityQueue寫法:對象
import java.util.*; public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) { if (input == null || k <= 0 || k > input.length) { return new ArrayList<Integer>(); } Queue<Integer> queue = new PriorityQueue<>(k, new Comparator<Integer>() { //降序 @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); for (int i = 0; i < input.length; i++) { if(queue.size() == k){ if(queue.peek() > input[i]){ queue.poll(); queue.add(input[i]); } }else{ queue.add(input[i]); } } ArrayList<Integer> list = new ArrayList<>(queue); return list; } }
本身實現大頂堆寫法:blog
import java.util.*; public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { ArrayList<Integer> list = new ArrayList<>(); if (input == null || k <= 0 || k > input.length) { return list; } int[] kArray = Arrays.copyOfRange(input,0,k); // 建立大根堆 buildHeap(kArray); for(int i = k; i < input.length; i++) { if(input[i] < kArray[0]) { kArray[0] = input[i]; maxHeap(kArray, 0); } } for (int i = kArray.length - 1; i >= 0; i--) { list.add(kArray[i]); } return list; } public void buildHeap(int[] input) { for (int i = input.length/2 - 1; i >= 0; i--) { maxHeap(input,i); } } private void maxHeap(int[] array,int i) { int left=2*i+1; int right=left+1; int largest=0; if(left < array.length && array[left] > array[i]) largest=left; else largest=i; if(right < array.length && array[right] > array[largest]) largest = right; if(largest != i) { int temp = array[i]; array[i] = array[largest]; array[largest] = temp; maxHeap(array, largest); } } }
如何獲得一個數據流中的中位數?若是從數據流中讀出奇數個數值,那麼中位數就是全部數值排序以後位於中間的數值。若是從數據流中讀出偶數個數值,那麼中位數就是全部數值排序以後中間兩個數的平均值。咱們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。
建立優先級隊列維護大頂堆和小頂堆兩個堆,而且小頂堆的值都大於大頂堆的值,2個堆個數的差值小於等於1,因此當插入個數爲奇數時:大頂堆個數就比小頂堆多1,中位數就是大頂堆堆頭;當插入個數爲偶數時,使大頂堆個數跟小頂堆個數同樣,中位數就是 2個堆堆頭平均數。也可以使用集合類的排序方法。
import java.util.Comparator; import java.util.PriorityQueue; public class Solution { PriorityQueue<Integer> minHeap = new PriorityQueue<>(); PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2.compareTo(o1); } }); int count = 0; public void Insert(Integer num) { count++; //當數據個數爲奇數時,進入大根堆 if((count & 1) == 1){ minHeap.add(num); maxHeap.add(minHeap.poll()); }else{ maxHeap.add(num); minHeap.add(maxHeap.poll()); } } public Double GetMedian() { if(count == 0){ return null; } // 當數據個數是奇數時,中位數就是大根堆的頂點 if ((count & 1) == 1) { return Double.valueOf(maxHeap.peek()); } else { return Double.valueOf((minHeap.peek() + maxHeap.peek())) / 2; } } }