剑指40_最小的k个数

import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
	//受上一题的启发,同样找到index为k-1的数字,左边都是小于的数字
        ArrayList<Integer> list=new ArrayList<Integer>();
        int len=input.length;
		if(input==null||len<1||k>len||k<=0) return list;
        int start=0;
        int end=len-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++){
            list.add(input[i]);
        }
        return list;
    }
    public int Partition(int[] array,int lo,int hi){
        int tmp=array[lo];
        while(lo<hi){
            while(array[hi]>=tmp&&lo<hi) hi--;
            array[lo]=array[hi];
            while(array[lo]<=tmp&&lo<hi) lo++;
            array[hi]=array[lo];
        }
        array[hi]=tmp;
        return hi;
    }
}

利用快排的思想,但是这样会该变原有的数组,注意最开始的边界条件判断,当k<=0或k>len时,这种方法会改变原有的数组,适合数据量比较小,时间复杂度为O(n),23ms


import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list=new ArrayList<Integer>();
        int len=input.length;
		if(input==null||len<1||k>len||k<=0) return list;
		//引入TreeSet,是按照红黑树的形式维护一个按照升序排列的set
        TreeSet<Integer> tree=new TreeSet<Integer>();
        for(int i=0;i<len;i++){
            tree.add(input[i]);
        }
        int i=0;
        for(Integer num:tree){
            if(i==k) break;
            list.add(num);
            i++;
        }
        return list;
    }
}

利用TreeSet维护一个按照升序排好的Set,之后取出前k个即可,但是要求数组不能有重复数字。27ms

import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list=new ArrayList<Integer>();
        int len=input.length;
		if(input==null||len<1||k>len||k<=0) return list;
		int[] maxHeap=new int[k];
        //初始化堆
        for(int i=0;i<maxHeap.length;i++){
            maxHeap[i]=input[i];
        }
        //将初始化的堆调整为最大堆,最后一个不为叶子节点的节点开始
        for(int i=(maxHeap.length-1)/2;i>=0;i--){
            adjustHeap(maxHeap,i);
        }
        for(int i=k;i<len;i++){
            if(maxHeap[0]>input[i]){
                maxHeap[0]=input[i];//将堆的最大元素替换,重新赋值更小的元素
                adjustHeap(maxHeap,0);
            }
        }
        for(int i=0;i<maxHeap.length;i++){
            list.add(maxHeap[i]);
        }
        return list;
		
    }
    //调整最大堆的函数
    static void adjustHeap(int maxHeap[],int i){//数组保存是从0开始,最后一位的索引是len-1,所以它的上一位是len-1/2
        int index=i;
        int lchild=2*i+1;//注意与[0,n]的区别
        int rchild=2*i+2;
        int len=maxHeap.length;
        if(index<=(len-1)/2){
            //寻找子节点中最大的节点
            if(lchild<=(len-1)&&maxHeap[index]<maxHeap[lchild]){
                index=lchild;
            }
            if(rchild<=(len-1)&&maxHeap[index]<maxHeap[rchild]){
                index=rchild;
            }
            //此时的index一定指向最大的元素
            //将节点与最大的节点进行交换
            if(i!=index){//如果index仍然等于i,则表明该子结构已经是最大堆
                int tmp=maxHeap[index];
                maxHeap[index]=maxHeap[i];
                maxHeap[i]=tmp;
                //交换后子树可能不满足最大堆,递归调整?
                adjustHeap(maxHeap,index);//调整子树的最大堆结构
            }
        }
    }
}

利用大顶堆来保存k个数字,取大顶堆中的顶部最大数字,如果接下来插入的数字大于顶部,那么它肯定不是最小的k个数字,如果,它小于顶部的最大数字,那么就将其插入,代替顶部元素,调整最大堆,是顶部元素为最大值。

不断地将小于大顶堆的最大数字插入堆中,将小于顶部元素插入,这样,这个大顶堆就是所有数字中最小的k个数。


利用最大堆,时间复杂度为O(nlogk),20ms,不改变原有数据,适合与海量数据。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值