剑指offer第二版——面试题40(java)

面试题:最小的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=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=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

 

你可能感兴趣的:(剑指offer第二版)