最小的k個數 劍指office原題

輸入n個整數,找出其中最小的K個數

2016-07-06 14:10:51

問題:輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。

分析:

同樣最直接的簡單方法就是先給這n個整數先排序,排序之後位於最前面的K個數就是最小的K個數,結合考慮到的邊界條件和錯誤處理。簡單編碼如下:

importjava.util.ArrayList;

importjava.util.Collections;

publicclass Solution {

    public ArrayListGetLeastNumbers_Solution(int [] input, int k) {

       if(input.length<=0||k<=0||input.length

            return newArrayList();

        ArrayList list=newArrayList();

        ArrayList newlist=newArrayList();

        for(int i=0;i

               list.add(input[i]);

            }

        if(input.length==k)

            return list;

        Collections.sort(list);

        for(int i=0;i<=k-1;i++){

            newlist.add(list.get(i));

        }

        return newlist;

    }

}

但是算法複雜度爲O(nlogn),試着優化,提出更快的算法,如果基於數組的第K個數字來調整,使得比第K個數字小的所有數字位於數組的左邊,比第K個數字大的所有數字位於數組的右邊。這樣調整後。位於數組左邊的K個數字就是最小的K個數字(這K個數字不一定是排序的)。基於這個思路,算法複雜度降爲了O(n),編碼如下:

importjava.util.ArrayList;

publicclass Solution {

    public ArrayListGetLeastNumbers_Solution(int [] input, int k) {

       if(input.length<=0||k<=0||input.length

            return newArrayList();

        int start=0,end=input.length-1;

        int index=Partition(input,start,end);

        while(index!=k-1){

            if(index>k-1){

                end=index-1;

               index=Partition(input,start,end);

            }else{

                start=index+1;

               index=Partition(input,start,end);

            }

        }

        ArrayList list=newArrayList();

        for(int i=0;i

            list.add(input[i]);

        return list;

    }

    public static int Partition(int[] input,intstart,int end){

        int pivot=(int)(Math.random()*(end-start)+start);

        swap(input[pivot],input[end]);

        int small=start-1;

        for(pivot=start;pivot

            if(input[pivot]

                small++;

                if(small!=pivot)

                    swap(input[pivot],input[small]);

            }

        }

        small++;

        swap(input[small],input[end]);

        return small;

    }

    private static void swap(int x,int y){

        int temp=x;

        x=y;

        y=temp;

    }

}

但是在通過時有錯誤,不明白錯在哪裏,正確運行無錯的代碼如下:

importjava.util.ArrayList;

publicclass Solution {

    public ArrayListGetLeastNumbers_Solution(int [] input, int k) {

        ArrayList aList = new ArrayList();

        if(input.length == 0 || k >input.length || k <= 0)

            return aList;

        int low = 0;

        int high = input.length-1;

        int index =Partition(input,k,low,high);

        while(index != k-1){

            if (index > k-1) {

                high = index-1;

                index =Partition(input,k,low,high);

            }else{

                low = index+1;

                index =Partition(input,k,low,high);

            }

        }

        for (int i = 0; i < k; i++)

            aList.add(input[i]);

        return aList;

    }

    

    int Partition(int[] input,int k,int low,inthigh){

        int pivotkey = input[k-1];

        swap(input,k-1,low);

        while(low < high){

            while(low < high &&input[high] >= pivotkey)

                high--;

            swap(input,low,high);

            while(low < high &&input[low] <= pivotkey)

                low++;

            swap(input,low,high);

        }

        return low;

    }

 

 

    private void swap(int[] input, int low, inthigh) {

        int temp = input[high];

        input[high] = input[low];

        input[low] = temp;

    }

}

 

進一步思考,如果數據很大,面對海量數據時,能不能使得時間複雜度較低且快速完成任務?我們可以先創建一個大小爲K的數據容器來存儲最小的K個數字,接下來我們每次從輸入的n個整數中讀入一個數。如果容器中已有的數字少於K個,則直接把這次讀入的整數放入到容器中;如果容器中已有K個數字了,就說明容器已滿,此時我們不能再插入新的數字而只能替換已有的數字。當容器滿了,我們要做三件事:一是在K個整數中找到最大數;二是有可能在這個容器中刪除最大數;三是有可能插入一個新的數。找到已有的K個數中的最大值,然後拿這次待插入的整數和最大值進行比較。如果待插入的值比當前已有的最大值小,則用這個數替換當前已有的最大值;如果待插入的值比當前已有的最大值還要大,那麼這個數不可能是最小的K個整數之一,我們拋棄這個整數。選擇不同的二叉樹來實現這個容器,自然想到的就是最大堆或紅黑樹。按照該方法編寫代碼如下:

importjava.util.ArrayList;

importjava.util.Iterator;

importjava.util.TreeSet;

publicclass Solution {

    public static ArrayListGetLeastNumbers_Solution(int[] input, int k) {

        ArrayList leastNum = newArrayList();

        if (input == null || input.length <1 || k < 1 || k > input.length)

            return leastNum;

        TreeSet kSet = newTreeSet();

        for (int i = 0; i < input.length;i++) {

            if (kSet.size() < k) {

                kSet.add(input[i]);

            } else {

                if (input[i] < kSet.last()){

                    kSet.remove(kSet.last());

                    kSet.add(input[i]);

                }

            }

        }

        Iterator it =kSet.iterator();

        while (it.hasNext()) {

            leastNum.add(it.next());

        }

        return leastNum;

    }

}

比較後兩種改進的算法,如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章