剑指Offer——最小的K个数

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

思路一:利用快速排序的parition函数。如果基于数组的第K个数字来调整,则使得比第K个数字小的所有数字都位于数组的左边,比第K个数字大的所有数字都位于数组的右边,调整之后,位于数组中左边的K个数字就是最小的K个数字(这K个数字不一定是排序的,这只是快速排序的第一趟排序)。时间复杂度为O(n)

注意点:考虑数组为空的情况,以及K<0或者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==null||input.length==0||k<=0||k>input.length){
            return list;
        }
        
        int start=0;
        int end=input.length-1;
        int index=partition(input,start,end);
        while (index!=k-1){
            if(index>k-1){
                end=index-1;
                index=partition(input,start,end);
            }else{
                start=index+1;
                index=partition(input,start,end);
            }
        }
        for(int i=0;i<k;i++){
            list.add(input[i]);
        }
        return list;
    }
    
    public  int partition(int[] arr, int startIndex, int endIndex) {
        // 取第一个位置的元素作为基准元素
        int pivot = arr[startIndex];
        int left = startIndex;
        int right = endIndex;
        while( left != right) {
            //控制right指针比较并左移
            while(left<right && arr[right] > pivot){
                right--;
            }
            //控制right指针比较并右移
            while( left<right && arr[left] <= pivot) {
                left++;
            }
            //交换left和right指向的元素
            if(left<right) {
                int p = arr[left];
                arr[left] = arr[right];
                arr[right] = p;
            }
        }
        //pivot和指针重合点交换
        arr[startIndex] =arr[left];
        arr[left] = pivot;
        return left;
    }
}

 

思路二:利用大顶堆。新创建一个大小为K的容器,对该容器进行操作,适合海量数据处理;

利用大顶堆来存储最小的K个数字,如果新遍历的数字比堆顶元素小,则删除堆顶元素,添加遍历到的元素。

堆排序思想可参考:堆排序算法  https://blog.csdn.net/AnNing_007/article/details/99639127

代码:

import java.util.ArrayList;
public class Solution {
    public static ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list=new ArrayList<Integer>();
        if(input==null||input.length==0||k<=0||input.length<k){
            return list;
        }
        int [] newArray=new int[k];
        for(int i=0;i<k;i++){
            newArray[i]=input[i];
        }
        //1.构建大顶堆
        for(int i=k/2-1;i>=0;i--){
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(newArray,i,k);
        }
        for(int i=k;i<input.length;i++){
            if(input[i]<newArray[0]){
                swap(newArray,0,k-1);
                newArray[k-1]=input[i];
                //for(int j=k/2-1;j>=0;j--)
                    //从第一个非叶子结点从下至上,从右至左调整结构
                adjustHeap(newArray,0,k);
            }
        }
        for(int i=0;i<k;i++){
            list.add(newArray[i]);
        }
        return list;
    }
    /**
     * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
     * @param arr
     * @param i 第一个非叶子节点
     * @param length 数组的长度
     */
    public static void adjustHeap(int []arr,int i,int length){
        int temp = arr[i];//先取出当前元素i
        for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
            if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                arr[i] = arr[k];
                i = k;
            }
        }
        arr[i] = temp;//将temp值放到最终的位置
    }

    //交换
    public static void swap(int[] arr, int n, int m) {
        int temp = arr[n];
        arr[n] = arr[m];
        arr[m] = temp;
    }

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值