最小的K个数

题目

输入n个整数,找出其中最小的k个数。

例如

输入4,5,1,6,2,7,3,8

输出1,2,3,4

思路

思路一

排序后取出前k个数。时间复杂度为O(nlgn)

思路二

依然根据快速排序中交换数据的方法,被选取的数字被交换的位置,该位置前面的数都比被选取的小,该位置后面的都比选取的大,所以只要找到第k个位置就好。代码见下。

时间复杂度O(n)

思路三

我们可以先创建一个k个容量的容器,每次读取一个数字,如果该容器没满,就将该数组放进容器。如果该容器已满,则得到该容器中的最大值,如果读取的数字大于等于最大值,则读取下一个数字,否则,删除最大值,将读取的数组放进容器,所有数字读取完毕后容器中的K个数字为最小。

需要思考,怎样得到k个容器中的最大值以及删除插入的操作的复杂度,选用合适的数据结构使得复杂度最小。

可以用最大堆,得到最大值的复杂度为O(1),删除和插入数字的复杂度为O(lgK),java中封装好的PriorityQueue即可使用。

也可以使用红黑树,得到最大值,删除,插入的复杂度都为O(lgk)

总的时间复杂度为O(nlgk).

代码见下。

代码

思路二

public static int[] getLeastNumbers(int[] numbers,int length,int k){

    if(numbers == null || length <= 0 || k <= 0 || k > length)return null;


    int[] result = new int[k];
   
int start = 0;
   
int end = length - 1;
   
int index = partition(numbers,start,end);
   
while(index != k){
       
if(index < k){
            start = index +
1;
            index = partition(numbers,start,end);
        }
else{
            end = index -
1;
            index = partition(numbers,start,end);
        }
    }
   
for(int i = 0;i < k;i++){
        result[i] = numbers[i];
    }
   
return result;
}

public static int partition(int[] numbers,int start,int end){
   
while(start < end) {
       
while (numbers[end] >= numbers[start] && start < end) end--;
       
int temp =  numbers[end];
        numbers[end] = numbers[start];
        numbers[start] = temp;
       
while (numbers[end] >= numbers[start] && start < end) start++;
        temp =  numbers[end];
        numbers[end] = numbers[start];
        numbers[start] = temp;
    }
   
return start;
}

思路三

public static int[] getLeastNumbers2(int[] numbers,int length,int k){

    if(numbers == null || length <= 0 || k <= 0 || k > length)return null;



    PriorityQueue<Integer> result = new PriorityQueue<>(k, new Comparator<Integer>() {

        @Override

        public int compare(Integer o1, Integer o2) {

            return o2.compareTo(o1);

        }

    });

    int[] results = new int[k];

    for(int i = 0;i < k;i++){

        result.offer(numbers[i]);

    }

    for(int i = k;i < length;i++){

        int max = result.peek();

        if(numbers[i] < max){

            result.poll();

            result.offer(numbers[i]);

        }

    }

    for(int i = 0;i < k;i++){

        int max = result.poll();

        results[i] = max;

    }

    return results;

}

总结

思路一最直观,但是时间复杂度相对较高。

思路二时间复杂度最低,但是需要修改输入的数组。

思路三需要用到最大堆或者红黑树,需要对数据结构掌握熟悉,但是特别适合处理海量数据,因为可以一个一个处理数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值