剑指offer上的一道题:输入n个整数,找出最小的k个数。例如输入4、5、1、6、2、7、3、8共8个数,最小的4个数为:1、2、3、4。
分析:
解法一:
可以把它看车数组排序问题,先对数组排序,再取数组前k个数。各个排序算法中,快排是性价比比较高的了,时间事件复杂度为O(n*logn)。还有没有其他解法呢?
解法二:
快排思想派上用场了。快排算法中,我们通常要找一个参考元素,针对这个元素把数组分为俩个子数组。元素左边的子数组小于该元素,元素右边的子数组小于该元素。对了!只要找到一个元素使得他左边的子数组个数为k就可以了。
这种解法最坏的时间复杂度也才O(n*logn),是不是比第一种解法好多了!
解法三:
怎么能忘了堆排呢,构建一个k个元素的小顶堆,不停的往里面插入元素。最后堆里的元素就是我们要求的K个最小元素。这种解法的好处是没有移动数组中的元素。但却开辟了额外的空间。
基于解法三的Java解法:
构建K个堆的过程太过复杂了,Java里提供了很多集合,我们可以用起来撒!
下面的代码就是我利用TreeSet构建的一个小顶堆,为什么要用TreeSet?嘿嘿,不深究了,不同的同学可以看看红黑树。TreeSet默认的排序是一个由大到小的二叉树,怎么办呢?重写Comparable接口。
1)自定义一个类MyInteger,将int封装进去;
2)自定义MyInteger实现Comparable接口,大小关系颠倒;
3)将数组插入TreeSet,读取前K个数组元素即可;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class KMinNumber
{
static class MyInteger implements Comparable<MyInteger>
{
Integer i;public MyInteger(int i)
{
this.i=i;
}
@Override
public int compareTo(MyInteger o)
{
// TODO Auto-generated method stub
if (i>o.getI())
{
return 1;
}
else if (i==o.getI())
{
return 0;
}
else
return -1;
}
@Override
public String toString()
{
// TODO Auto-generated method stub
return i.toString();
}
public Integer getI()
{
return i;
}
}
public static void main(String[] args)
{
int[] a=new int[20];for (int i = 0; i < a.length; i++)
{
a[i]=(int)(Math.random()*100);
System.out.print(a[i]+" ");
}
findKMin(a,5);
}
public static void findKMin(int[] a, int k)
{
TreeSet<MyInteger> treeSet=new TreeSet<>();for (int i = 0; i < a.length; i++)
{
MyInteger integer=new MyInteger(a[i]);
treeSet.add(integer);
}
System.out.println();
int i=0;
Iterator<MyInteger> iterator=treeSet.iterator();
while(i<k&&iterator.hasNext())
{
i++;
System.out.print(" "+iterator.next().toString());
}
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。