leetcode:最小的k個數

題目來源:力扣

題目描述:

輸入整數數組 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。

審題:

對於TopM問題,當數據量較小時,可以直接對數據進行排序,然後選擇前k個數值即可.而對於海量大數據,例如十億,百億的數據量,如果要找出前10個數值,則使用排序算法是不現實的.因爲海量的數據時可能無法一次性裝進內存,更別提後續的排序過程了.

TopM問題的經典處理方法是基於優先隊列進行解決.如果要出道最小的k個數,我們可以向向最大優先隊列依次插入數值,如果插入後隊列中元素個數大於k,則彈出最大的元素.最終當插入完所有元素後,隊列中剩餘的k個元素即是最小的k個值. 對上述步驟可以略做調整,如果當前隊列中元素個數等於:如果當前元素小於隊列中最大元素,則插入該元素,然後刪除最大元素,如果當前元素大於最大元素,則不插入該元素.

優先隊列通常使用堆結構實現,在該篇文章中,我們將使用數組構建最大堆,以實現最大優先隊列.

java算法:

class Solution {
    //基於最大堆實現優先隊列
    //爲了選擇最小的k個數,我們需要保存所有k+1個值
    //爲了便於計算父節點下標與子節點下標,我們從下標1開始存儲元素
    private int[] pq;
    int pqSize;
    
    //插入最底部,然後上浮
    private void insert(int x){
        pq[++pqSize] = x;
        int i = pqSize;
        while(i > 1){
            if(pq[i] > pq[i/2]){
                int tmp = pq[i];
                pq[i] = pq[i/2];
                pq[i/2] = tmp;
                i = i/2;
            }
            else
                break;
        }
    }

	//下沉
    private int delMax(){
        int max = pq[1];
        pq[1] = pq[pqSize--];
        if(pqSize > 0){
            int i = 1;
            while(i <= pqSize / 2){
                //選擇最大的子節點
                if(pq[2*i] < pq[2*i+1]){
                    if(pq[i] < pq[2*i+1]){
                        int tmp = pq[i];
                        pq[i] = pq[2*i+1];
                        pq[2*i+1] = tmp;
                        i = 2*i+1;
                    }
                    else
                        break;
                }
                else if(pq[i] < pq[2*i]){
                    int tmp = pq[i];
                    pq[i] = pq[2*i];
                    pq[2*i] = tmp;
                    i = 2*i;
                }
                else
                    break;
            }
        }
        return max;
    }

    public int[] getLeastNumbers(int[] arr, int k) {
        pq = new int[k+2];
        for(int val: arr){
            if(pqSize < k){
                insert(val);
            }
            else{
                if(val < pq[1]){
                    insert(val);
                    delMax();
                }
            }
        }
        int[] minK = new int[k];
        System.arraycopy(pq, 1, minK, 0, k);
        return minK;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章