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());
  }
 }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章