剑指offer之:40最小的k个数
题目描述:
输入n个整数,找出其中最小的k个数。例如,输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
解法一:
把输入的n个整数进行排序,排序后位于前面的k个数就是最小的k个数。时间复杂度O(nlogn)(快排)。此方法只适用于我们可以修改输入的数组时。基于Partition。
解法二:
不能修改输入的数组时,我们可以是用最大堆。时间复杂度是O(nlogk)。适合处理海量数据。
我们首先创建一个大小为k的数据容器来存储最小的k个数字,接下来每次从输入的n个整数中读入一个数字。如果容器中已有的数字少于k个,则读取时直接存入容器;如果容器中已有k个数字了,就说明容器已满,此时我们就不能再插入新的数字而只能替换已有的数字。找出已有的k个数中的最大值。然后拿这次待插入的数和最大值相比。如果待插入的数比已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的数比已有的最大值还大,就可以抛弃。
因此,容器满了以后有3件事要做:1.在k个整数中找到最大数;2.有可能在这个容器中删除最大数;3.有可能要插入一个新的数字。如果使用一棵二叉树来实现这个容器,可以再O(logk)时间内实现这3步。故,对于n个输入的数字而言,总的时间效率就是O(nlogk)。
最大堆:根节点得值总是大于它的子树中任意节点的值。于是我们可以在O(1)时间内得到已有的k个数字中的最大值,但是需要O(logk)时间完成删除以及插入操作。
代码块:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Solution {
public static ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> rst = new ArrayList<Integer>();
if(input.length < k || k <= 0 ){
return rst;
}
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for(int i = 0; i < input.length; i++){
if (maxHeap.size() < k){
maxHeap.offer(input[i]);
}else if(maxHeap.peek() > input[i]){
Integer temp = maxHeap.poll();
temp = null;
maxHeap.offer(input[i]);
}
}
for(Integer integer : maxHeap){
rst.add(integer);
}
return rst;
}
public static void main(String[] args) {
int input[] = {4,5,1,6,2,7,3,8};
int k = 4;
ArrayList a = (ArrayList) GetLeastNumbers_Solution(input, k);
System.out.println(a);
}
}
解法三:
最大堆代码比较困难,可以采用红黑树(确保树在一定程度上是平衡的)来实现我们的容器。在STL(standard Template Library标准模板库:1.算法2.容器3.函数4.迭代器)中,set和multiset都是基于红黑树实现的。
代码块
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeSet;
public class Solution2redblacktree {
public static ArrayList GetLeastNumbers(int[] input, int k){
ArrayList<Integer> list = new ArrayList<Integer>();
if(input.length <=0 || k <=0 || input.length < k){
return list;
}
TreeSet<Integer> kSet = new TreeSet<Integer>();
for(int i = 0 ; i < input.length; i++){
if(kSet.size() < k){
kSet.add(input[i]);
}else if(input[i] < kSet.last()){
kSet.remove(kSet.last());
kSet.add(input[i]);
}
}
Iterator<Integer> iterator = kSet.iterator();
while(iterator.hasNext()){//不是if
list.add(iterator.next());
}
return list;
}