题目:输入n个整数,找出其中最小的K个数
思路:剑指中提供了两种不同时间复杂度的思路和代码。
思路1:我们可以利用快速排序的思路解决这个问题。如果基于数组的第K个数字来调整,则使得比第K个数字小的所有数字 都位于数组的左边,比第K个数字大的都位于数组的右边。这样调整后,位于数组中左边K个数字就是最小的k个数字(这k个数字不一定是排序的)。这个思路的时间复杂度是O(n),但是需要修改输入的数组。
代码链接:https://blog.csdn.net/shakespeare001/article/details/51280814
代码1:
public ArrayList
if(input == null)
return null;
ArrayList
if(k > input.length) //k大于数组的长度,返回空链表
return list;
int low = 0;
int high = input.length - 1;
int index = partition(input,low,high); //以第一个元素作为划分的元素,返回它在排序后数组中的位置
while(index != k-1){
if(index > k-1){ //如果返回的位置在k-1的右边
high = index - 1;
}else{ //返回的位置在k-1的左边
low = index + 1;
}
index = partition(input,low,high); //重新划分
}
for(int i = 0; i < k; i++){ //当返回的位置正好等于k-1时,将结果保存到list中
list.add(input[i]);
}
return list;
}
//划分操作
public int partition(int[] array,int start,int end){
int pivot = array[start]; //将第一个元素作为划分节点保存起来
while(start < end){
while(start < end && array[end] >= pivot) end--; //从后往前找到第一个比pivot小的元素
array[start] = array[end]; //这块不是采用的交换而是直接覆盖掉
while(start < end && array[start] <= pivot) start++;//从前往后找到第一个比pivot大的元素
array[end] = array[start];
}
array[start] = pivot; //把pivot放在正确的位置上
return start;
}
思路2:我们可以先创建一个大小为k的数据容器来存储最小的k个数字,接下来每次从输入的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入到容器中;如果容器中已经有k个数字了,此时需要替换已有的数字。找出这已有的k个数字中的最大值,然后拿这次待插入的整数和最大值进行比较,如果比当前的最大值小,则替换已有的最大值;如果大的话,可以抛弃这个整数。我们可以使用最大堆(堆排序),也可以使用红黑树来完成这个容器的创建。
这种思路的时间复杂度是O(nlogk)。这种解法虽然慢一些,但是有两个明显的优点:(1)没有修改输入的数据(2)该算法非常适合海量数据的输入。
以下代码使用了java中的TreeSet,它实现了红黑树的功能,底层使用TreeMap实现的,其中的数据会按照插入顺序自动升序排列。
代码2:
public static ArrayList
if(input == null)
return null;
ArrayList
if(k > input.length)
return list;
TreeSet
for(int i = 0 ; i < input.length; i++){
tree.add(input[i]);
}
int i = 0;
for(Integer elem : tree){
if(i >= k)
break;
list.add(elem);
i++;
}
return list;
}
代码3:这个是最大堆中的代码
public ArrayList
ArrayList
if (input == null || k <= 0 || k > input.length) {
return list;
}
int[] kArray = Arrays.copyOfRange(input,0,k);//复制原数组的0到k个,但是不包括k
// 创建大根堆
buildHeap(kArray); //构建一个堆,其中对顶元素是k个数中最大 的一个元素
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);
}
}