求一个数组中最小的K个数
思路1:利用快排的思想
思路2:利用堆的思想
1:快排思想
快排的核心是patition,该函数返回的是基准在该趟排序后的位置,并且能保证在该下标之前的所有元素都不比它大,在下标之后的所有元素都不比它小。
假设取k=4,n=10,如果patiton返回的index恰好为4
此时数组[a1,a2,a3,a4,X,b1,b2,b3,b4,b5],此时前k小元素就是index<4之前的那4个元素,递归结束(an<=X && bn>=X)
如果patition返回的index大于4(比如说5)
此时数组[a1,a2,a3,a4,a5,X,b1,b2,b3],则继续对左边进行patition
同理index小于4时,则继续对右边进行patition
patition的实现采用填坑法:
1:取数组第一个位置为基准,先保存该基准,并挖坑。
2:从数组尾开始找第一个小于该基准的值填上旧坑,并且该位置变成新的坑
3:从数组头开始找第一个大于该基准的值填上旧坑,并且该位置变成新的坑
重复2~3直到i>=j为止
eg:
[ 3 , 2 , 7 , 6 , 6 , 1 , 2 , 5 ] temp=3
[ 坑 , 2 , 7 , 6 , 6 , 1 , 2 , 5 ] 找到第一个小于基准3的数2
i j
[ 2 , 2 , 7 , 6 , 6 , 1 , 坑 , 5 ] 找到第一个大于基准3的数7
i j
[ 2 , 2 , 坑 , 6 , 6 , 1 , 7 , 5 ] 找到第一个小于基准3的数1
i j
[ 2 , 2 , 1 , 6 , 6 , 坑 , 7 , 5 ] 找到第一个大于基准3的数6
i j
[ 2 , 2 , 1 , 坑 , 6 , 6 , 7 , 5 ] 在i<j的情况下,从右边往左边已经找到小于基准3的数了
i j
[ 2 , 2 , 1 , 3 , 6 , 6 , 7 , 5 ] 将基准3填在最后的坑上,此时保证index<3的数都不大于3,index>3的数都不小于3
public static int patition(int[] nums, int left, int right) {
int temp = nums[left];
while (left < right) {
while (left < right && nums[right] >= temp) {
right--;
}
if (left < right) {
nums[left] = nums[right];
}
while (left < right && nums[left] <= temp) {
left++;
}
if (left < right) {
nums[right] = nums[left];
}
}
nums[left] = temp;
return left;
}
public static void main(String[] args) {
int[] nums = { 1, 2, 4, 3, 9, 7, 6, 8, 5, 9, 6 };
int k = 4;
int index = 0;
int left = 0;
int right = nums.length - 1;
while (index >= 0 && index < nums.length) {
index = patition(nums, left, right);
if (index == k) {
System.out.println("使用patition方法求TOP_K_MIN:");
for (int i = 0; i < index; i++)
System.out.print(nums[i] + " ");
System.out.println();
break;
} else if (index > k) {
right = index - 1;
} else {
left = index + 1;
}
}
}
2:堆的思想
同样以k=4、n=10为例,在长度为10的数组中找最小的4个
先取下标为0~3的元素,创建一个大顶堆max_heap
此时max_heap[0]为数组前4元素中的最大值
再遍历下标4~9的元素,如果有比max_heap[0]小,则insert
insert操作实际是把新元素覆盖到堆顶,然后进行堆调整,使其满足大顶堆性质
public static int[] getTopKByHeap(int input[], int k) {
int heap[] = createHeap(input, k);
for (int i = k; i < input.length; i++) {
if (input[i] < heap[0]) {
insert(heap, input[i]);
}
}
return heap;
}
public static int[] createHeap(int a[], int k) {
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = a[i];
}
for (int i = 1; i < k; i++) {
int child = i;
int parent = (i - 1) / 2;
int temp = a[i];
while (parent >= 0 && child != 0 && result[parent] < temp) {
result[child] = result[parent];
child = parent;
parent = (parent - 1) / 2;
}
result[child] = temp;
}
return result;
}
public static void insert(int a[], int value) {
a[0] = value;
int parent = 0;
while (parent < a.length) {
int lchild = 2 * parent + 1;
int rchild = 2 * parent + 2;
int minIndex = parent;
if (lchild < a.length && a[parent] < a[lchild]) {
minIndex = lchild;
}
if (rchild < a.length && a[minIndex] < a[rchild]) {
minIndex = rchild;
}
if (minIndex == parent) {
break;
} else {
int temp = a[parent];
a[parent] = a[minIndex];
a[minIndex] = temp;
parent = minIndex;
}
}
}
public static void main(String[] args) {
int[] nums = { 1, 2, 4, 3, 9, 7, 6, 8, 5, 9, 6 };
int k = 4;
int result[] = getTopKByHeap(nums, k);
System.out.println("使用max_heap方法求TOP_K_MIN:");
for (int i = 0; i < result.length; i++) {
System.out.print(result[i] + " ");
}
}