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