剑指offer-test29

29.最小的K个数(涉及堆排序)
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
1.堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
堆排序的基本思路:
  a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
  c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

//一般升序采用大顶堆,降序采用小顶堆)
//这里构造大顶堆:大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> minnums=new ArrayList<>();
        if(input==null||k<=0||k>input.length){
            return minnums;
        }
        //(1) 遍历输入数组,将前k个数插入到推中;
        int[] nums=new int[k];//用于放最小的k个数
        for(int i=0;i<k;i++){
            nums[i]=input[i];//先放前k个数
        }
        for(int i=k/2-1;i>=0;i--){
            adjustHeap(nums,i,k-1);//将数组造成最大堆形式
        }
        // 继续从输入数组中读入元素做为待插入整数,并将它与堆中最大值比较:
        //如果待插入的值比当前已有的最大//值小,则用这个数替换当前已有的最大值;
        //如果待插入的值比当前已有的最大值还大,则抛弃这个数,继续读下一个数。
        for(int i=k;i<input.length;i++){
            if(input[i]<nums[0]){
                nums[0]=input[i];
                adjustHeap(nums,0,k-1);//重新调整最大堆
            }
        }
        for(int n:nums){
            minnums.add(n);
        }
        return minnums;
    }
    private void adjustHeap(int[] arr,int start,int length){
        int temp=arr[start];
        int child=start*2+1;
        while(child<=length){
            if(child+1<=length&&arr[child+1]>arr[child]){//如果右子结点大于左子结点,则指向右子结点
                child++;
            }
            if(arr[child]<temp){
                break;
            }
            //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
            arr[start]=arr[child];
            start=child;
            child=child*2+1;
        }
        arr[start]=temp;//将temp值放到最终的位置
    }

基于堆排序算法,构建最大堆。时间复杂度为O(nlogk)
(1) 遍历输入数组,将前k个数插入到推中;(利用multiset来做为堆的实现)
(2) 继续从输入数组中读入元素做为待插入整数,并将它与堆中最大值比较:如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,则抛弃这个数,继续读下一个数。
这样动态维护堆中这k个数,以保证它只储存输入数组中的前k个最小的数,最后输出堆即可。

2.如果用快速排序,时间复杂度为O(nlogn);

3.如果用冒泡排序,时间复杂度为O(n*k)

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> alist=new ArrayList<Integer>();
        if(k>input.length) {
            return alist;
        }
        for(int i=0;i<k;i++){
            for(int j=0;j<input.length-i-1;j++){
                if(input[j]<input[j+1]){
                    int temp=input[j];
                    input[j]=input[j+1];
                    input[j+1]=temp;
                }
            }
            alist.add(input[input.length-i-1]);
        }
        return alist;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值