java——最小的K个数

题目链接

牛客在线oj题——最小的K个数

题目描述

给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。

数据范围:0≤k,n≤10000,数组中每个数的大0≤val≤1000
要求:空间复杂度 O(n) ,时间复杂度 O(nlogk)

题目示例

示例1

输入:
[4,5,1,6,2,7,3,8],4

返回值:
[1,2,3,4]

说明:
返回最小的4个数即可,返回[1,3,2,4]也可以

示例2

输入:
[1],0

返回值:
[]

示例3

输入:
[0,1,2,1,2],3

返回值:
[0,1,1]

解题思路

这道题是一个典型的topK问题,可以直接使用任意一种排序,将数组中的元素排成从小到大的顺序,然后直接返回前k个数字

而更好的解法是,构造一个含k个元素的大根堆,先讲数组的前k个元素插入到堆中,然后继续从左到右遍历数组中的元素

大根堆的特性是:堆顶元素比下面所有元素都要大

当遍历到的元素i比大根堆堆顶的元素peek大时,说明i肯定不是最小的k个数之中的元素,继续遍历下一个位置

当遍历到的元素i比大根堆堆顶的元素peek小时,说明peek肯定不是最小的k个数中的元素,把大根堆堆顶元素弹出,将i插入到大根堆中

遍历完整个数组序列,最终大根堆中所有元素就是最小的k个数

例如:
在这里插入图片描述
首先将前四个元素插入大根堆
在这里插入图片描述
当前遍历到的元素是2,比大根堆堆顶元素6小,将6弹出,将2入大根堆,i++
在这里插入图片描述
当前遍历到的元素是7,比大根堆堆顶元素5大,肯定不在最小的k个数中,继续遍历
在这里插入图片描述
当前遍历到的元素为3,比大根堆堆顶元素5小,将5弹出大根堆,将3插入到大根堆中
在这里插入图片描述
当前遍历到的元素是8,比大根堆堆顶元素4大,肯定不在最小的k个数中,遍历结束,当前大根堆中存放的所有元素就是最小的k个数

完整代码

import java.util.*;

public class Solution {
    
    
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
    
    
        ArrayList<Integer> result = new ArrayList<>();
        if(input == null || k <= 0 || k > input.length){
    
    
            return result;
        }
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k, Collections.reverseOrder());
        for (int i = 0; i < input.length; i++){
    
    
            if(i < k){
    
    
                priorityQueue.offer(input[i]);
            } else {
    
    
                if(input[i] < priorityQueue.peek()){
    
    
                    priorityQueue.poll();
                    priorityQueue.offer(input[i]);
                }
            }
        }
        for (int i = 0; i < k; i++){
    
    
            result.add(priorityQueue.poll());
        }
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_60867520/article/details/130387001