【剑指Offer】29、最小的K个数

  题目描述:

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

  解题思路:

  本题最直观的解法就是将输入的n个整数排序,排序之后位于最前面的k个数就是最小的k个数,这取决于排序的时间复杂度,最快为O(nlogn)。

  当我们可以对输入的数组进行修改时,可以得到一种更快的解法。类似于快速排序的思想,基于Partition函数来解决这个问题,如果我们选取数组的第n个数字(记为key)来进行数组重排,那么比key小的所有数字都位于数组的左边,比key大的所有数字都位于key之后,也就是数组的右边。

  因此,我们只需要判断key的下标是否等于k-1,等于时返回其左边的K个数便是最小的K个数。当key的下标小于k-1时,就在右边继续划分,反之左边继续划分。由此我们可以得到以下代码实现,时间复杂度为O(n)。

  编程实现(Java):

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        //方法一:排序
        //方法二:partition分组
        ArrayList<Integer> res=new ArrayList<>();
        if(input==null || input.length<=0 || k>input.length)
            return res;
        int len=input.length;
        int low=0,high=len-1;
        int index=-1;
        while(low<high && index!=k){
            index=partition(input,low,high);
            if(index>k)
                high=index-1;
            else
                low=index+1;
        }

        for(int i=0;i<k;i++)
            res.add(input[i]);
        return res;
    }
    //划分算法,返回的i左边都比他小,右边都比他大
    public int partition(int[] array,int low,int high){
        int i=low,j=high;
        int temp=array[low];
        
        while(i<j){
            while(i<j && array[j]>=temp)
                j--;
            if(i<j){
                array[i]=array[j];
                i++;
            }
            while(i<j && array[i]<temp)
                i++;
            if(i<j){
                array[j]=array[i];
                j--;
            }
        }
        array[i]=temp;
        return i;
    }
}
posted @ 2019-05-05 11:21  gzshan  阅读(1408)  评论(0编辑  收藏  举报