面试题 17.14. 最小K个数 - 力扣(LeetCode)
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]
提示:
0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))
java
public class 最小K个数_堆 {
public int[] smallestK(int[] arr, int k) {
// 取前K个数放到数组中
int[] tree = new int[k];
for (int i = 0; i < k; i++) {
tree[i] = arr[i];
}
if (k <= 1) {
return tree;
}
// 建立一个最小堆
buildHeap(tree);
// 入堆
for (int i = k; i < arr.length; i++) {
if (arr[i] <= tree[0]) {
tree[0] = arr[i];
// 重新排序
heapify(tree, 0);
}
}
return tree;
}
// 堆排序
void heapify(int[] tree, int index) {
// 重新为当前节点及其子七点排序(最小元素正常的过程)
if (index >= tree.length) {
return;
}
// 记录最小父节点、左子节点及右子节点最小值的下标
int max = index;
int left = 2 * index + 1;
if (left < tree.length && tree[max] < tree[left]) {
max = left;
}
int right = 2 * index + 2;
if (right < tree.length && tree[max] < tree[right]) {
max = right;
}
// 不是父节点时交换父节点也子节点值后重新为子节点排序
if (max != index) {
swap(tree, max, index);
heapify(tree, max);
}
}
// 构建堆
void buildHeap(int[] arr) {
for (int i = (arr.length + 1) / 2; i >= 0; i--) {
heapify(arr, i);
}
}
// 交换
void swap(int[] tree, int a, int b) {
int d = tree[a];
tree[a] = tree[b];
tree[b] = d;
}
}