1. 数据流中第K大的数据
解法一:记录前K个的最大值:每次进来一个比K个值里面最小值大的数,踢出K个值里面最小的那个数,把最新的那个数记录进K个值里面(先排序,使用快排),快排的时间复杂度是KlogK,有k个值,所以该解法的复杂度为O(N*K(logK))
解法二:使用优先队列(priorityQueue)维持一个小顶堆(min heap)
java中的优先队列,priorityQueue的作用是保证每次取出的元素都是队列中权值最小的。其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值)
public class HeapData {
private PriorityQueue<Integer> pq = null;
private int k;
public int add(int val) {
if(pq.size() < k)//如果队列中的数量少于K,直接添加入优先队列,优先队列会自动维持小顶堆
pq.offer(val);
else{
if(pq.peek() < val){//否则队列中的数量大于或者等于K,优先队列中的最小数字小于新的数据,优先队列中的顶堆要被移除,并且添加入新的数据进优先队列
pq.poll();
pq.offer(val);
}
}
return pq.peek();//返回当前第K大的数
}
public HeapData(int k, int[] nums) {
this.k = k;
pq = new PriorityQueue<>(k);
for(int i : nums){//对传进来的int数组遍历
add(i);
}
}
}
维持小顶堆的时间复杂度是Log2K,遍历的有N个数据,所以时间复杂度为O(Nlog2K)
2. 最小的K个数
输入n个整数,找出其中最小的K个数。例如 输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路1:
-
1、使用最大堆,构建容量为K的最大堆
-
2、遍历数组,每次比较数组中的元素与堆顶元素大小,堆堆顶小入堆即可
public static ArrayList<Integer> getLeastNumbers_Solution(int [] input, int k) { ArrayList<Integer> ret = new ArrayList<>(); if (input == null || k == 0) { return ret; } int len = input.length; if (len < k) { return ret; } // 构建大顶堆 PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>(){ @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); // 遍历数组,把比堆顶元素小的元素加入最大堆中 for (int i=0; i<len; i++) { int curVal = input[i]; System.out.println(maxHeap.size()+",curlval:"+curVal); if (maxHeap.size() < k) { maxHeap.add(curVal); } else { // 堆顶元素大于当前元素,则弹出堆顶元素,加入当前元素到堆中 if (maxHeap.peek() > curVal) { maxHeap.poll(); maxHeap.add(curVal); } } } // 最大堆所有元素加入要返回的list中 ret.addAll(maxHeap); return ret; }