【经典面试题】无序数组中,求第K大的数(堆、荷兰国旗问题、bfprt算法)

本文介绍了三种解决寻找无序数组中第K大元素的算法:堆排序、优化的荷兰国旗问题和bfprt算法。堆排序时间复杂度为O(N*logK),而优化的荷兰国旗问题和bfprt算法则能达到O(N)。bfprt算法通过精心选取基准值,确保了高效性能。

今天来看一到算法题!经典面试题了,将从时间复杂度一般的解法,再到最优解!!!

img

题目:查找一个无序数组中,第K大的数。LeetCode链接

image-20211230194300686

解法一、堆

分析:既然是求第K大的数,那么很显然,可以使用TOPK问题的角度来解题。只需建一个小根堆,堆的大小就是K,遍历一遍数组:

  • 如果此时堆的大小<K,直接往里面放数据。
  • 如果此时堆的大小>=K,那么只需比较堆顶与arr[i]的大小,如果堆顶的元素小于arr[i],就弹出堆顶,再放入arr[i]即可。

image-20211230200419392

public int findKthLargest(int[] nums, int k) {
   
   
    if (nums == null || nums.length == 0 || k <= 0 || k > nums.length) {
   
   
        return -1;
    }
    PriorityQueue<Integer>  minHeap = new PriorityQueue<>();
    int size = 0; //堆的大小
    for (int i = 0; i < nums.length; i++) {
   
   
        if (size < k) {
   
    //堆的大小 < K 
            size++;
            minHeap.add(nums[i]);
        } else {
   
   //堆的大小 >= K 
            if (minHeap.peek() < nums[i]) {
   
   
                minHeap.poll();
                minHeap.add(nums[i]); //放入比较大的元素
            }
        }
    }
    return minHeap.poll();
}

以上这种解法,因为整体遍历了一遍数组,是O(N),而遍历的每一个数,插入堆中最坏的情况就是O(logK),整体时间复杂度O(N*logK),空间复杂度O(K)这样的效率,还是达不到面试官的要求。我们接着看下一解法。

解法二、改进“荷兰国旗问题”

我们在之前学快速排序的时候,说到过一个优化,就是荷兰国旗问题优化。当时说的是根据一个基准值,将整个区域划分为大于区、小于区和等于区,此时这里也是一样的。我们既然要找第K大的数,对应在数组中,那就是下标为K-1的数据。

说到这里,我想你可能就理解我的意思了。

那就是,根据划分后的区域,小于区、等于区和大于区,判断K-1,是在这三个区域的哪一块区域内:

  • K-1在等于区范围内,那么直接返回等于区的数据即可。
  • K-1在大于区范围内,那么递归调用函数,再次进行划分即可。
  • K-1在小于区范围内,也是递归调用小于区的范围即可。

如图:

image-20211230201631195

//主方法
public int findKthLargest(int[] nums, int k) {
   
   
    if (nums == null || nums.length == 0 || k <= 0 || k > nums.length) {
   
   
        return -1;
    }
    //因为process函数求的是第K小的数,而题目是要求第K大的数
    //所以此时调用的是计算第length-k小的数
    
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听雨7x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值