剑指Offer对答如流系列 - 最小的k个数

面试题40:最小的k个数

一、题目描述

输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

二、问题分析

最容易想到的方法就是排序,取相应数字的元素即可(注意去重)。我这里为了方便直接使用了快排来做这个去重,你可以使用Set集合来做去重,更方便而且效率更高。

想拉开与别人的差距,难免需要优化时间效率,我们可以这样做:依次遍历n个整数,用一个容器存放最小的k个数字,每遇到比容器中最大的数字还小的数字时,将最大值替换为该数字。容器可以使用最大堆或者红黑树来实现。堆相比红黑树更容易实现,我们这里采用堆。

三、问题解答

思路一(不推荐)

    public ArrayList<Integer> GetLeastNumbers(int [] input, int k) {
        ArrayList<Integer> leastNumbers = new ArrayList<>();
        if(input==null || k<=0 || k>input.length) {
            return leastNumbers;
        }

        int start=0;
        int end=input.length-1;
        int index=partition(input,start,end);

        while(index!= k-1){
            if(index< k-1){
                start=index+1;
                index=partition(input,start,end);
            }else{
                end=index-1;
                index=partition(input,start,end);
            }
        }
        for(int i=0;i<k;i++){
            leastNumbers.add(input[i]);
        }
        return leastNumbers;
    }

    private int partition(int[] arr, int start,int end){
        int pivotKey=arr[start];
        while(start<end){
            while(start<end && arr[end]>=pivotKey) {
                end--;
            }
            swap(arr,start,end);
            while(start<end && arr[start]<=pivotKey){
                start++;
            }
            swap(arr,start,end);
        }
        return start;
    }

    private void swap(int[] arr, int i,int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }

思路二(推荐)

  public ArrayList<Integer> GetLeastNumbers(int [] input, int k) {
        ArrayList<Integer> leastNumbers = new ArrayList<>();
        if(input==null || k<=0 || k>input.length) {
            return leastNumbers;
        }
        int[] numbers=new int[k];  //用于放最小的k个数
        //先放入前k个数
        System.arraycopy(input, 0, numbers, 0, k);

        for(int i = k/2-1; i>=0; i--){
            adjustHeap(numbers,i,k-1);//将数组构造成最大堆形式
        }
        for(int i = k; i<input.length; i++){
            if(input[i]<numbers[0]){ //存在更小的数字时
                numbers[0]=input[i];
                adjustHeap(numbers,0,k-1);//重新调整最大堆
            }
        }
        for(int n:numbers)
            leastNumbers.add(n);
        return leastNumbers;
    }

    //最大堆的调整方法
    private void adjustHeap(int[] arr,int start,int end){
        int temp=arr[start];
        int child=start*2+1;
        while(child<=end){
            if(child+1<=end && arr[child+1]>arr[child]) {
                child++;
            }
            if(arr[child]<temp) {
                break;
            }
            arr[start]=arr[child];
            start=child;
            child=child*2+1;
        }
        arr[start]=temp;
    }
发布了158 篇原创文章 · 获赞 3221 · 访问量 46万+

猜你喜欢

转载自blog.csdn.net/qq_42322103/article/details/104109944