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个数。