A题之找K个最小的数

    剑指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());
  }
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值