描述
给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
0 <= k <= input.length <= 10000
0 <= input[i] <= 10000
示例1
输入:[4,5,1,6,2,7,3,8],4
返回值:[1,2,3,4]
说明:返回最小的4个数即可,返回[1,3,2,4]也可以
示例2
输入:[1],0
返回值:[]
示例3
输入:[0,1,2,1,2],3
返回值:[0,1,1]
解体思路
思路一
直接排序。
代码如下:
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
Arrays.sort(input);
ArrayList<Integer> integers = new ArrayList<>();
for (int i = 0; i < k; i++) {
integers.add(input[i]);
}
return integers;
}
复杂度分析:
时间复杂度:O(
N
log
N
N\log N
NlogN),快速排序复杂度。
空间复杂度:O(
N
N
N)。
思路二
堆排序,建立个k大小的最大堆,依次排序,代码如下:
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> res = new ArrayList<>(k);
if (k == 0) {
return res;
}
int[] heap = new int[k + 1];
for (int i = 1; i < k + 1; i++) {
heap[i] = input[i - 1];
}
buildMaxHeap(heap, heap.length);
for (int i = k; i < input.length; i++) {
if (heap[1] > input[i]) {
heap[1] = input[i];
adjustDown(heap, 1, heap.length);
}
}
for (int i = 0; i < k; i++) {
res.add(heap[i + 1]);
}
return res;
}
public void buildMaxHeap(int[] arr, int length) {
for (int i = (length - 1) / 2; i > 0; i--) {
adjustDown(arr, i, arr.length);
}
}
public void adjustDown(int[] arr, int k, int length) {
int tmp = arr[k];
for (int i = 2 * k; i < length; i *= 2) {
if (i + 1 < length && arr[i] < arr[i + 1]) {
i++;
}
if (arr[i] < tmp) {
break;
} else {
arr[k] = arr[i];
k = i;
}
}
arr[k] = tmp;
}
复杂度分析:
时间复杂度:O(
N
log
K
N\log K
NlogK),K大小的堆,遍历一次。
空间复杂度:O(
N
N
N)。
思路三
与堆排序类似,因为二叉排序树是特殊的堆,所以可以用TreeMap代替堆,从而减少代码量,代码如下:
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> res = new ArrayList<>(k);
if (k == 0) {
return res;
}
TreeMap<Integer, Integer> resultTreeMap = new TreeMap<>();
int count = 0;
for (int i = 0; i < input.length; i++) {
if (count < k) {
resultTreeMap.put(input[i], resultTreeMap.getOrDefault(input[i], 0) + 1);
count++;
continue;
}
Map.Entry<Integer, Integer> lastEntry = resultTreeMap.lastEntry();
if (lastEntry.getKey() > input[i]) {
if (lastEntry.getValue() == 1) {
resultTreeMap.remove(lastEntry.getKey());
} else {
resultTreeMap.put(lastEntry.getKey(), lastEntry.getValue() - 1);
}
resultTreeMap.put(input[i], resultTreeMap.getOrDefault(input[i], 0) + 1);
}
}
Set<Map.Entry<Integer, Integer>> entries = resultTreeMap.entrySet();
for (Map.Entry<Integer, Integer> entry : entries) {
Integer entryCount = entry.getValue();
for (int i = 0; i < entryCount; i++) {
res.add(entry.getKey());
}
}
return res;
}
复杂度分析:
时间复杂度:O(
N
log
K
N\log K
NlogK),K大小的堆,遍历一次。
空间复杂度:O(
N
N
N)。