题目
- 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,
思路
- 根据左神的荷兰国旗代码快速排序
- 然后将最小的K的数字写入到建立的容器ArrayList resultlist中
- 最后输出结果 ,但是这种需要每次改动数组的位置,如果不需要改变位置,那么快排的方式就不允许了
- 基于堆排序算法,构建最大堆。时间复杂度为O(nlogk)
- 如果用快速排序,时间复杂度为O(n);
- 如果用冒泡排序,时间复杂度为O(n*k)
代码
-
快排,改变数组位置的方式,时间复杂度为:O(n)
-
思路一:利用快速排序中的获取分割(中轴)点位置函数getPartitiion。
基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。调整之后,位于数组左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。O(N)
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] arr, int k) {
ArrayList<Integer> resultlist = new ArrayList<Integer>();
if (arr == null || arr.length < 2 || k > arr.length) {
return resultlist;
}
quickSort(arr, 0, arr.length - 1);
for(int i=0;i<k;i++){
resultlist.add(arr[i]);
}
return resultlist;
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
int[] p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1);
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
swap(arr, ++less, l++);
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);
} else {
l++;
}
}
swap(arr, more, r);
return new int[] { less + 1, more };
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
-
思路二:利用堆排序,O(N logK),适合处理海量数据
-
(1) 遍历输入数组,将前k个数插入到推中;(利用multiset来做为堆的实现)
-
(2) 继续从输入数组中读入元素做为待插入整数,并将它与堆中最大值比较:如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,则抛弃这个数,继续读下一个数。
-
这样动态维护堆中这k个数,以保证它只储存输入数组中的前k个最小的数,最后输出堆即可
-
自己确定前k个元素的最大值,不使用最大堆
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<Integer>();
if(input.length < k || k == 0)
return list;
for (int i = 0; i < k; i++)
list.add(input[i]);
for (int i = k; i < input.length; i++) {
int j = this.getMax(list);
int temp = (Integer) list.get(j);
if (input[i] < temp)
list.set(j, input[i]);
}
return list;
}
public int getMax(ArrayList<Integer> list) {
int max = list.get(0);
int j = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) > max) {
max = list.get(i);
j = i;
}
}
return j;
}
}
- 乔戈里 使用大根堆,时间复杂度O(nlogk),适用于处理海量的数据
import java.util.*;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> resultList = new ArrayList<>();
if(k > input.length || k<=0)
return resultList;
//使用优先级队列建堆,优先级队列默认是最小堆,所以要重写比较器
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>(){
public int compare(Integer o1,Integer o2){
return o2.compareTo(o1);
}
}
);
for(int i=0;i<input.length;i++)
{
if(i < k){//如果没有达到k个数,那么直接入堆
maxHeap.add(input[i]);
}else{
if(maxHeap.peek() > input[i])
{//堆顶的数比数组当前的数大,那么就堆顶出堆
maxHeap.poll();
maxHeap.add(input[i]);//把当前数加入堆中
}
}
}
while(maxHeap.isEmpty() != true)
resultList.add(maxHeap.poll());//把堆中的数出堆添加到结果数组中
return resultList;
}
}