面试题:最小的k个数
题目:输入n个整数,找出其中最小的k个数,例如,输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4
【方法一】
将整数排序,排序后位于最前面的k个数则为最小的k个数。时间复杂度为O(nlogn)
【方法二——需要修改数组】
可以基于快排的部分算法来解决问题(Partition)。
可基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组左边的k个数字就是最小的k个数字
【方法三】
创建一个大小为k的数据容器,用于存储最小的k个数字。
每次从输入的n个整数中读入一个数,如果容器中已有数字少于k个,则将该数放入容器。
如果容器中已有k个数字,则找出已有k个数中的最大值,与待插入数字做比较,放入更小的数。
因此,在容器已满时,需要做的事包括:
1)找到最大数
2)删除最大数
3)插入新数
可用二叉树来实现该容器,这样可在O(logk)时间内实现上面步骤,因此对n个输入数字来说,总时间复杂度O(nlogk)
用二叉树来实现容器时,由于需要快速找到k个整数的最大数,因此使用最大堆来实现。(找到最大数是因为需要移除最大数)
在最大堆中,根节点的值总是大于它的子树中的任意节点值。
构造堆/调整堆: https://blog.csdn.net/xiao__gui/article/details/8687982
代码
【方法一】
排序方法在网上挺多的 直接排序之后输出前k个数字即可
【方法二】
public class Q40 {
public static void main(String[] args) {
int[] l = new int[] {4,5,1,6,2,7,3,8,0,-1};
int[] mink = minK(l,5);
}
public static int[] minK(int[] l,int k) {
int start = 0;
int end = l.length-1;
int loc = findLoc(l, start, end);
while(loc!=k) {
if(loc>k) {
end = loc-1;
loc = findLoc(l, start, end);
}
if(loc<k) {
start = loc+1;
loc = findLoc(l, start, end);
}
}
int[] newl = new int[k];
for(int i=0;i<k;i++) {
newl[i]=l[i];
System.out.printf("%d ",l[i]);
}
return newl;
}
public static int findLoc(int[] l, int start, int end) {
int loc = start++;
while(start<end) {
while(l[start]<=l[loc] && start <end) {
start++;
}
while(l[end]>=l[loc] && start < end) {
end--;
}
int temp = l[end];
l[end--] = l[start];
l[start++] = temp;
}
int t = l[end];
l[end] = l[loc];
l[loc] = t;
return end;
}
}
【方法三】
public class Q40_2 {
public static void main(String[] args) {
int[] l = new int[] {4,5,1,6,2,7,3,8};
int[] s = minK(l,5);
showList(s);
}
public static int[] minK(int[] l,int k) {
int[] lk = new int[k];
for(int i=0;i<k;i++) {
lk[i] = l[i];
}
buildHeap(lk);
int loc = k;
while(loc<l.length) {
if(l[loc]<lk[0]) {
lk[0]=l[loc];
heapify(0, lk);
}
loc++;
}
return lk;
}
// 建堆
public static void buildHeap(int[] l) {
for(int i=l.length/2-1;i>=0;i--) {
heapify(i, l);
}
}
// 调堆
public static void heapify(int i,int[] l) {
int left = i*2+1;
int right = i*2+2;
int biggest = i;
if(left < l.length && l[left]>l[i]) {
biggest = left;
}
if(right<l.length && l[biggest]<l[right]) {
biggest = right;
}
if(i == biggest) {
return;
}
swap(biggest, i, l);
heapify(biggest, l);
}
// 交换数组中两个数
public static void swap(int i,int j,int[] l) {
int temp = l[i];
l[i] = l[j];
l[j] = temp;
}
// 打印数组
public static void showList(int[] l) {
for(int i=0;i<l.length;i++) {
System.out.printf("%d ",l[i]);
}
System.out.println();
}
}