Java刷题之最小k个数的思路及具体实现

 更新时间:2024年10月08日 10:56:07   作者:小川_wenxun  
这篇文章主要介绍了Java刷题之最小k个数的思路及具体实现,最小K个数是一个经典的top-K问题,可以通过整体排序、建立小根堆或大根堆的方式解决,排序方式时间复杂度较高,适合数据量小的场景,小根堆适合k较小的情况,文中通过代码介绍的非常详细,需要的朋友可以参考下

力扣链接:面试题 17.14. 最小K个数 - 力扣(LeetCode)

题目描述:

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

<strong>输入:</strong> arr = [1,3,5,7,2,4,6,8], k = 4
<strong>输出:</strong> [1,2,3,4]

思路:

这个问题属于是一类问题中,即top-K问题:N个数据中,前k个最大/最小的元素,一般来说k比较小;或者是需要找到这组数据中 第k大/第k小 的数据。

根据这道的要求,我们可以有以下三种思路:

整体排序

整体建立一个大小为N的小根堆

把前K个元素创建为大根堆,遍历剩下的N-K个元素,和堆顶元素比较,如果比堆顶元素学校,则堆顶元素删除,但前元素入堆

具体实现

整体建立一个大小为N的小根堆

通过创建一个小根堆,把要全部元素都放进去,然后再把前k个元素提出来即可。

class Solution {
    public int[] smallestK(int[] arr, int k) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        for(int i = 0; i < arr.length; i++){
            priorityQueue.offer(arr[i]);
        }

        int[] ret = new int[k];
        for(int i = 0; i < k; i++){
            ret[i] = priorityQueue.poll();
        }

        return ret;
    }
}

由PriorityQueue创建的堆默认为小根堆,所以把元素直接放进去,priorityQueue会默认成为小根堆,然后再把前k个元素放到ret数字里即可。

通过大根堆实现

这里有一个要做的地方:让PriorityQueue可以实现大根堆。

 通过 按住Crtl 鼠标点击 PriorityQueue 可以看到其中实现的方法,再Crtl  鼠标点击 Comparator,看Comparator接口中的方法,

可以看到其中有个 compare方法,这便是通过比较 o1,o2的值来进行小根堆的实现,这里我们可以通过重写compare方法来实现大根堆。这里选择的是创建一个新类来实现。

class IntCmp implements Comparator<Integer> {

    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
}

然后把前K个元素放进大根堆,如果根节点的值大于可能要放进来的值,则把根节点删除,把该值放进来,同时PriorityQueue会保证该堆一直为大根堆。最后遍历完N-K个值后,再把这些值返回出去。

其中的过程大概如上图所示。

class Solution{
    public int[] smallestK(int[] arr, int k) {
    int[] ret = new int[k];
    if(arr == null || k == 0) return ret;
    PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntCmp());

    for (int i = 0; i < k; i++) {
        priorityQueue.offer(arr[i]);
    }

    for (int i =k; i < arr.length; i++) {
        int peekVal = priorityQueue.peek();
        if(peekVal > arr[i]) {
            priorityQueue.peek();
            priorityQueue.offer(arr[i]);
        }
    }

    for (int i = 0; i < k; i++) {
        ret[i] = priorityQueue.poll();
    }
    return ret;
    }
}

完整代码

第一种方法,通过小根堆实现

//时间复杂度为:O((k+1)logN)
class Solution {
    public int[] smallestK(int[] arr, int k) {
                PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        //时间复杂度为O(N*logN)
        for (int i = 0; i < arr.length; i++) {
            priorityQueue.offer(arr[i]);
        }
        
        //时间复杂度为O(K*logN)
        int[] ret = new int[k];
        for (int i = 0; i < k; i++) {
            ret[i] = priorityQueue.poll();
        }
        
        return ret;
    }
}

第二种方法,通过大根堆实现

class IntCmp implements Comparator<Integer> {

    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
}

class Solution{
    public int[] smallestK(int[] arr, int k) {
    int[] ret = new int[k];
    if(arr == null || k == 0) return ret;
    PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntCmp());

    for (int i = 0; i < k; i++) {
        priorityQueue.offer(arr[i]);
    }

    for (int i =k; i < arr.length; i++) {
        int peekVal = priorityQueue.peek();
        if(peekVal > arr[i]) {
            priorityQueue.peek();
            priorityQueue.offer(arr[i]);
        }
    }

    for (int i = 0; i < k; i++) {
        ret[i] = priorityQueue.poll();
    }
    return ret;
    }
}

总结 

到此这篇关于Java刷题之最小k个数的思路及具体实现的文章就介绍到这了,更多相关Java算法题最小k个数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • java进制转换工具类实现减少参数长度

    java进制转换工具类实现减少参数长度

    这篇文章主要为大家介绍了java进制转换工具类实现减少参数长度示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Java中的LinkedHashSet和TreeSet解读

    Java中的LinkedHashSet和TreeSet解读

    这篇文章主要介绍了Java中的LinkedHashSet和TreeSet解读,哈希表和链表实现的set接口哈希表决定了它元素是唯一的,而链表则保证了他是有序的(存储和取出顺序一致),元素按照一定规则排序,不是按储存时间排的,需要的朋友可以参考下
    2023-09-09
  • SpringBoot中操作Bean的生命周期的方法总结

    SpringBoot中操作Bean的生命周期的方法总结

    在SpringBoot应用中,管理和操作Bean的生命周期是一项关键的任务,这不仅涉及到如何创建和销毁Bean,还包括如何在应用的生命周期中对Bean进行精细控制,本文给大家总结了SpringBoot中操作Bean的生命周期的方法,需要的朋友可以参考下
    2023-12-12
  • 详解Java编程中static关键字和final关键字的使用

    详解Java编程中static关键字和final关键字的使用

    这篇文章主要介绍了详解Java编程中static关键字和final关键字的使用,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • Java 解析线程的几种状态详解

    Java 解析线程的几种状态详解

    这篇文章主要为大家详细介绍了Java 解析线程的几种状态,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • 腾讯云部署javaWeb项目的实现步骤

    腾讯云部署javaWeb项目的实现步骤

    本文主要介绍了腾讯云部署javaWeb项目的实现步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • SpringBoot+vue实现登录图片验证码功能

    SpringBoot+vue实现登录图片验证码功能

    这篇文章主要给大家介绍一下如何SpringBoot+vue实现登录图片验证码功能,文中有详细的代码示例,具有一定的参考价值,需要的朋友可以参考下
    2023-07-07
  • 使用Netty快速实现一个群聊功能的示例详解

    使用Netty快速实现一个群聊功能的示例详解

    这篇文章主要为大家详细介绍了如何利用 Netty 框架开发一个 WebSocket 服务端,从而实现一个简单的在线聊天功能,感兴趣的小伙伴可以了解下
    2023-11-11
  • IDEA自动清理类中未使用的import包的操作方法

    IDEA自动清理类中未使用的import包的操作方法

    在项目开发中,经常会引入很多未使用的import包,这不仅增加了编译时间,还会使代码可读性变差,设置IDEA自动清理未使用的import包,可以提高代码的可读性,本文给大家介绍IDEA自动清理类中未使用的import包的方法,感兴趣的朋友一起看看吧
    2024-09-09
  • SpringBoot项目实战之数据交互篇

    SpringBoot项目实战之数据交互篇

    这篇文章主要给大家介绍了关于SpringBoot项目实战之数据交互篇的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03

最新评论