题目

  • 输入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;
   }
}