算法刷题:经典TopK问题整理

本文详细解析了TopK问题中的经典算法,包括快速排序的优化版、堆排序以及桶排序。通过实例展示了如何利用这些方法找到数组中第K大的元素,同时介绍了各自的时间复杂度和空间复杂度。适合算法学习者提升排序算法理解与实战能力。
摘要由CSDN通过智能技术生成


前言

本篇记录笔者在算法刷题的过程中遇到的经典TopK问题

一、TopK问题定义

topK问题比较经典,在面试算法题中考察也比较普遍,无非就是在一群无序的数中,找到最小的K个数和最大的K个数

本篇以寻找最大的K个数为样板进行整理
在这里插入图片描述

二、解法

1.快速排序

面对topK问题,最能直接了当想到的做法便是排序,而后根据顺序用下标访问该元素即可

本篇侧重解法,关于快排原理本篇就不进行推导,有兴趣的小伙伴可以自行调研

代码如下:

class Solution {
public:
    int findKth(vector<int> q, int n, int K) {
        quick_sort(q,0,q.size()-1);
        return q[n-K];
    }
    
    void quick_sort(vector<int> &q,int l,int r){
        if(l>=r) return;
        int x=q[l+r>>1];
        int i=l-1;
        int j=r+1;
        while(i<j){
            do i++;while(q[i]<x);
            do j--;while(q[j]>x);
            if(i<j)    swap(q[i],q[j]);
        }
        quick_sort(q, l, j);
        quick_sort(q, j+1,r);
        return;
    }
};

平均时间复杂度:O(nlogn)
空间复杂度:O(1)

2.快速排序优化版

我们观察到,其实快排中我们将数组分为了两部分,其实每一轮循环中,我们要找的第K个数,没有必要对整个数组进行寻找,可以对其中一侧进行寻找,从而达到优化的效果

代码如下

class Solution {
public:
    int findKth(vector<int> q, int n, int K) {
        return quick_sort(q,0,q.size()-1,n-K+1);
    }
    
    int quick_sort(vector<int> &q,int l,int r,int k){
        if(l>=r) return q[l];
        int x=q[l+r>>1];
        int i=l-1;
        int j=r+1;
        while(i<j){
            do i++;while(q[i]<x);
            do j--;while(q[j]>x);
            if(i<j)    swap(q[i],q[j]);
        }
        if(j-l+1>=k) return quick_sort(q, l, j,k);
        else return quick_sort(q, j+1,r,k-(j-l+1));
    }
};

平均时间复杂度:O(n)
空间复杂度:O(1)

3.堆排序

其实寻找到第K个数,同样可以通过维护一个堆来解决,众所周知,堆顶要么存放最大数,要么存放最小数,那么其实只要维护一个大顶堆,只要保证放入堆中的是n-K+1个数字,当堆中数量过多时,弹出堆顶,最后返回堆顶的数字即可

class Solution {
public:
    int findKth(vector<int> q, int n, int K) {
        priority_queue<int,vector<int>,less<int>> p;
        for(auto temp:q){
            p.push(temp);
            if(p.size()>n-K+1) p.pop();
        }
        return p.top();
    }
    
};

平均时间复杂度:O(nlog(n))
空间复杂度:O(n)

4.桶排序

桶排序相应定义如下

桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来记得到有序序列。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是比较排序,他不受到O(nlogn)下限的影响。

基本思想

桶排序的思想近乎彻底的分治思想。

桶排序假设待排序的一组数均匀独立的分布在一个范围中,并将这一范围划分成几个子范围(桶)。

然后基于某种映射函数f ,将待排序列的关键字 k 映射到第i个桶中 (即桶数组B 的下标i) ,那么该关键字k 就作为 B[i]中的元素 (每个桶B[i]都是一组大小为N/M 的序列 )。

接着将各个桶中的数据有序的合并起来 : 对每个桶B[i] 中的所有元素进行比较排序 (可以使用快排)。然后依次枚举输出 B[0]….B[M] 中的全部内容即是一个有序序列。

补充: 映射函数一般是 f = array[i] / k; k^2 = n; n是所有元素个数

为了使桶排序更加高效,我们可以做到这两点:

在额外空间充足的情况下,尽量增大桶的数量 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中

本篇更侧重代码解决,具体的动图演示和实现可以看这篇博客
桶排序


总结

以上就是笔者关于TopK问题的解决

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值