题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
题解:
1.暴力求解,数据量大当然会超时。将数组排序,然后遍历找到最小的K个数。(PS:K大于数组的长度时,输出应该为空的数组。)
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> arrayList = new ArrayList<>();
if (input != null && input.length > 0 && k <= input.length) {
Arrays.sort(input);
for (int i = 0; i < k; i++) {
arrayList.add(input[i]);
}
}
return arrayList;
}
}
2.数据量大,采用大根堆,或者小根堆解决Top K问题。
以大根堆为例,找Top K小的元素,先建立一个大小为K的大根堆,堆顶元素为堆最大值,然后后续的值与大根堆的堆顶的值进行比较,后续值比较小,则替换掉堆顶的元素,重新维护堆。依次类推,即堆中的元素即为Top K小的元素。
import java.util.ArrayList;
public class Main7 {
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> arrayList = new ArrayList<>();
if (input != null && input.length > 0 && k <= input.length) {
headSort(input, k);
for (int i = k - 1; i >= 0; i--)
arrayList.add(input[i]);
}
return arrayList;
}
public static void headSort(int arr[], int k) {
// 建立一个大小为k的大根堆
dump(arr, k);
for (int i = k; i < arr.length; i++) {
if (arr[0] > arr[i]) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
// 重新维护堆
dump(arr, k);
}
}
}
public static void dump(int arr[], int k) {
// 初始化堆
for (int i = k / 2 - 1; i >= 0; i--) {
// 从第一个非叶子节点开始
adjust(arr, i, k);
}
// 将堆排序
for (int i = k - 1; i > 0; i--) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
adjust(arr, 0, i);
}
}
public static void adjust(int arr[], int parent, int size) {
// 获取当前节点值
int temp = arr[parent];
// 获取左孩子
int child = parent * 2 + 1;
while (child < size) {
// 判断是否有右孩子,右孩子的值是不是小于左孩子的值
if (child + 1 < size && arr[child] > arr[child + 1]) {
child++;
}
// 父节点大于他的孩子节点,不交换
if (temp <= arr[child]) {
break;
}
// 进行交换,比较新的孩子节点是否大于子孙节点
arr[parent] = arr[child];
parent = child;
child = 2 * child + 1;
}
arr[parent] = temp;
}
}