堆的应用(TOP-K问题)结合力扣算法题

TOP-K问题概念:

TOP-K问题概念:即求数据前k个最大或最小的的数据,一般数据量都很大。

TOP-K问题例子:

比如:前专业前10,世界五百强等等。

用堆解决TOP-K问题原因:

对于TOP-K问题,我们首先想到的就是排序,但是,当数据量非常大的时候,排序就不太可取了,后面讲到排序的时候你会发现,基本排序的时间复杂度都在O(nlogn)和O(n^2)之间,而我们只需要得到最大或最小的前k位,这样付出的代价很高。最佳的方式就是用堆来解决。

基本思路

  1. 用数据集合的前k个数据建堆
    • 前k个最小的元素,则建大堆
    • 前k个最大的元素,则建小堆
  2. 用剩余的n - k个元素依次和栈顶元素比较,满足则替换掉堆顶元素,然后再向下调整。
    思路分析:这里我就那前k个最小的元素来说了,用前k个数据建大堆后,堆顶为这个堆里最大的元素,当拿后面的元素和它比较时候,比它小的元素都将把它替换掉,然后向下调整,之后堆顶的数据还是最大的。根据这种思想可以知道,
    (1) 当前k个最小的元素和堆顶比较时候一定比堆顶小,所以一定会进堆。
    (2)当前k个最小的元素已经进堆了,没有元素比他们还小了,所以这个时候没有任何元素能进堆了,即堆里的数据就是前k个最小的元素。
    (3)而且这个时候堆顶为它们中最大的元素,那么堆顶就是第k小的元素,下面我要讲的力扣题就是这个问题。话不多说直接上题

力扣关于TOP-K问题的题:

力扣难度:中等
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
题目给出的接口:
红色<int findKthLargest(int* nums, int numsSize, int k) {
}>


void AdjustDown(int* arr, int n, int root){
    int parent = root;
    
/*此函数用了一个假设法:假设左孩子是比较小的结点,
但是如果右孩子数据小于左孩子的时候,
那么右孩子是比较小的结点,这样写是为了:
1.避免把左孩子小或者右孩子小分类,
如果左孩子小,然后怎么怎么样,
右孩子小怎么这么样,造成大量代码冗余。
2.如果把左右孩子分类的话,代码中出现大量左孩子,
右孩子,使读者或公司同事阅读不方便。
而用一个孩子表示较小的孩子,使代码阅读清晰明了。*/
    int child = parent * 2 + 1;//假设左孩子小
    while(child < n){
        if(child + 1 < n && arr[child + 1] < arr[child]){
            child++;
        }
        if(arr[child] < arr[parent]){
            int temp = arr[child];
            arr[child] = arr[parent];
            arr[parent] = temp;
            parent = child;
            child = parent * 2 + 1;
        }
        else{
            break;
        }
    }
}
int findKthLargest(int* nums, int numsSize, int k) {
    //将前k个元素先建小堆
    for(int i = (numsSize - 1 - 1) / 2; i >= 0; i--){
        AdjustDown(nums, k, i);
    }
    //用剩余的n - k个元素依次和栈顶元素比较
    for(int i = k; i < numsSize; i++){
    	//若该元素比堆顶大,则把堆顶的元素替换为该元素,然后向下调整,使堆顶元素还是最小的元素。
        if(nums[i] > nums[0]){
            nums[0] = nums[i];
            AdjustDown(nums, k, 0);
        }
    }
    //返回堆顶的元素即第k小的数据
    return nums[0];
}

谢谢你的阅读,喜欢的话点个赞转发一下吧!

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值