剑指offer:最小的K个数
Posted 一只菜鸡的奋斗史
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer:最小的K个数相关的知识,希望对你有一定的参考价值。
题意描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
解题思路
一、冒泡排序/选择排序
对数组进行排序,从数组中取出最小的k个数。不需要对数组全部排序,只需要找出前k个数即可。
二、快速排序
利用快速排序划分的思想,选择一个基数index
,将基数左右划分为两部分。
- 位于index左边的数字都小于index对应的值,右边都大于index指向的值
- 所以,当
index > k-1
时,表示k个最小数字一定在index的左边,此时,只需要对index的左边进行划分即可 - 当
index < k-1
时,说明index及index左边数字还没能满足k个数字,需要继续对k右边进行划分
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<Integer>(k);
if(input == null) //输入校验
return null;
if(k > input.length)
return list;
int low = 0;
int high = input.length - 1;
int index = partition(input,low,high); //划分数组,并找到基数所在的位置
while(index != k-1){
if(index > k-1){
high = index - 1; //向左划分
}else{
low = index + 1; //向右划分
}
index = partition(input,low,high); //继续划分数组,寻找基数所在位置
}
for(int i = 0; i < k; i++){
list.add(input[i]);
}
return list;
}
//划分操作
public int partition(int[] array,int start,int end){
int pivot = array[start]; //数组首位作为基数
//循环结束,将数组划分为两部分
while(start < end){
//从右向左查找,array[end] 《 pivot 的位置
while(start < end && array[end] >= pivot) end--;
//交换,放到左边
array[start] = array[end];
//从左向右查找,array[start] 》 pivot 的位置
while(start < end && array[start] <= pivot) start++;
//交换,放到右边
array[end] = array[start];
}
//start最后指向的位置 就是 基数所在位置
array[start] = pivot;
return start;
}
三、堆排序思想
-
可以先创建一个大小为k的数据容器来存储最小的k个数字,从输入的n个整数中一个一个读入放入该容器中,如果容器中的数字少于k个,则返回null
-
如果容器中已有k个数字,而数组中还有值未加入,此时就不能直接插入了,而需要替换容器中的值。按以下步骤进行插入:
- 先找到容器中的最大值
- 将待查入值和最大值比较,如果待查入值大于容器中的最大值,则直接舍弃这个待查入值即可;如果待查入值小于容器中的最小值,则用这个待查入值替换掉容器中的最大值
- 重复上述步骤,容器中最后就是整个数组的最小k个数字
对于这个容器的实现,我们可以使用最大堆的数据结构,最大堆中,根节点的值大于它的子树中的任意节点值。Java中的TreeSet类实现了红黑树的功能,它底层是通过TreeMap实现的,TreeSet中的数据会按照插入数据自动升序排列(按自然顺序)。因此我们直接将数据依次放入到TreeSet中,数组就会自动排序。
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if(input == null || k<=0 || k>input.length) return list; //输入校验
TreeSet<Integer> set = new TreeSet<>();
for(int i=0;i<input.length;i++){
set.add(input[i]); //数组元素添加入set
}
int i=0;
//取出前k个值
for(Integer item : set){
if(i >= k) break;
list.add(item);
i++;
}
return list;
}
以上是关于剑指offer:最小的K个数的主要内容,如果未能解决你的问题,请参考以下文章