三路快排解决TopK问题

前言:

我们首先要明白什么是三路快排,什么是topk问题。

三路快排:

思想:

三路快排就是数组分3块,三个指针,先随机取一个基准值key,然后将数组划分为3个部分:

【小于key】【等于key】【大于key】

此时key的值的位置就确定了,然后再递归遍历小于key部分,和大于key的部分。

具体实现:根据nums[i]的值分类讨论

优化:用随机的方式选择基准元素

随机的实现就是先用srand函数种下一个种子,然后再调用rand函数。

原码:

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        //种下随机数种子
        srand(time(NULL));
        int left = 0;
        int right = nums.size()-1;
        qsort(nums,left,right);
        return nums;
    }

    //随机生成比较元素key
    int GetRandom(vector<int>& nums,int left,int right)
    {
        int r = rand();
        int key = nums[r%(right-left+1) + left];//最后结果需要加上left
        return key;
    }

    void qsort(vector<int>& nums,int l,int r)
    {
        if(l >= r) return;//判断条件写在第一行
        int key = GetRandom(nums,l,r);
        int i = l;
        int left = l - 1;
        int right = r + 1;
        //一趟遍历,将key的值固定顺序
        while(i < right)//注意循环遍历条件
        {
            if(nums[i] == key) i++;
            else if(nums[i] > key)
            {
                swap(nums[i],nums[--right]);
            }
            else
            {
                swap(nums[i++],nums[++left]);
            }
        }
        //递归调用
        qsort(nums,l,left);
        qsort(nums,right,r);
    }
};

第二个问题:什么是topk问题?

topk问题一般分为两大类:

第一大类就是找最大/最小的第k个元素,这一类只需要找一个元素即可。

第二大类就是最大/最小的k个元素,这一类是找一串数字。

在有上面的知识后,我们先解决第一类问题如何找第k个元素。

第一类问题:

215. 数组中的第K个最大元素

题目描述:

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

解法:

一般topk问题我们也是可以用堆排序区解决,但是这道题目的时间复杂度要求是O(N),而我们的堆排序的时间复杂度是N*LOGN,所以仍然是我们快速排序的主场!

我们的算法是建立在三路快排的思想上,我们根据已经将数组分为三部分的基础上,根据每一部分元素的数量与k进行比较来去确定具体在哪一个区间。

原码:

class Solution {
public:
//三路快排
    int findKthLargest(vector<int>& nums, int k) {
        int left = 0,right = nums.size()-1;
        //随机数种子
        srand(time(NULL));;
        int ans = qsort(nums,left,right,k);
        return ans;
    }

    int GetRandom(vector<int>& nums,int left,int right)
    {
        int r = rand();
        //注意加上left
        return nums[r%(right-left+1) + left];
    }

    int qsort(vector<int>& nums,int l,int r,int k)
    {
        //为什么不用考虑大于的情况,因为后续会判断
        if(l == r) return nums[l];
        int left = l - 1;
        int right = r + 1;
        int i = l;
        //先将数组分为三块
        int key = GetRandom(nums,l,r);
        //因为是第k大,所以排降序
        while(i < right)
        {
            if(nums[i] == key) i++;
            else if(nums[i] < key) swap(nums[i++],nums[++left]);
            else swap(nums[i],nums[--right]); 
        }
        //分情况讨论,第k大元素具体在哪一段,直接return
        int c = r - right + 1,b = right - left - 1;
        if(c >= k) return qsort(nums,right,r,k);
        else if(b + c >= k) return key;
        else return qsort(nums,l,left,k-b-c);
    }
};

再解决第二类问题:

面试题 17.14. 最小K个数

题目描述:

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

解法:

这一题跟上一题寻找第K个元素,思想基本一样,都是将寻找的区间缩小,本题返回值是一串数字,直接返回{nums.begin(), nums.begin()+k}即可

原码:

class Solution {
public:
    //三路快排
    vector<int> smallestK(vector<int>& arr, int k) {
        srand(time(NULL));
        int left = 0,right = arr.size()-1;
        qsort(arr,left,right,k);
        //注意返回值的书写方式
        return {arr.begin(),arr.begin()+k};
    }

    int getRandom(vector<int>& arr,int left,int right)
    {
        int r = rand();
        return arr[r%(right-left+1) + left];
    }

    void qsort(vector<int>& arr,int l,int r,int k)
    {
        if(l >= r) return;
        int left = l - 1,right = r + 1;
        int key = getRandom(arr,l,r);
        int i = l;
        while(i < right)//不能等于!
        {
            if(arr[i] == key) i++;
            else if(arr[i] > key) swap(arr[i],arr[--right]);
            else swap(arr[i++],arr[++left]);
        }
        //分情况讨论
        //[l,left] [left+1,right-1] [right,r]
        int a = left - l + 1;
        int b = right - left - 1;
        if(k <= a) qsort(arr,l,left,k);
        else if(k <= a+b) return;
        else qsort(arr,right,r,k-a-b);
    }

};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/368068.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【八大排序】冒泡排序 | 快速排序 + 图文详解!!

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C语言进阶之路 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 交换排序一、冒泡排序1.1 算法步骤 动图演示1.2 冒泡排序的效率分析1.3 代码实现1.4 …

【Vue】组件间通信的7种方法(全)

目录 组件之前的通信方法 1. props/$emit 2.parent/children 3.ref 4.v-model 5.sync 6.attrs,attrs,attrs,listeners 7.provide/inject 7.eventBus 组件之前的通信方法 1. props/$emit 父传子 props 这个只能够接收父组件传来的数据 不能进行修改 可以静态传递 也可…

【计算机视觉】目标检测 |滑动窗口算法、YOLO、RCNN系列算法

一、概述 首先通过前面对计算机视觉领域中的卷积神经网络进行了解和学习&#xff0c;我们知道&#xff0c;可以通过卷积神经网络对图像进行分类。 如果还想继续深入&#xff0c;会涉及到目标定位(object location)的问题。在图像分类的基础上(Image classification)的基础上…

Maven快速入门——基础篇

本篇对Maven基础进行总结&#xff0c;主要对Maven的定义、作用、Maven坐标、依赖管理、依赖配置、依赖传递特性以及Maven的生命周期进行总结&#xff0c;后面会对springboot以及Maven高级进行总结。 文章目录 目录 一、Maven是什么&#xff1f; 二、Maven的作用&#xff1a; 三…

基于YOLOv8深度学习的水稻叶片病害智能诊断系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

openGauss学习笔记-213 openGauss 性能调优-总体调优思路

文章目录 openGauss学习笔记-213 openGauss 性能调优-总体调优思路213.1 调优思路概述213.2 调优流程 openGauss学习笔记-213 openGauss 性能调优-总体调优思路 213.1 调优思路概述 openGauss的总体性能调优思路为性能瓶颈点分析、关键参数调整以及SQL调优。在调优过程中&…

python使用两个栈实现队列

这里主要是使用两个栈来实现一个队列,并实现队列的入队和出队函数。 对于一个单词hello,如果正常情况下按照队列中先进先出的特点,会按照hello的顺序入队,同样也会按照hello的顺序出队。 添加图片注释,不超过 140 字(可选) 因此如果想要利用两个栈来形成队列,就要将后…

基于SpringBoot+Vue的高校在线答疑管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 二、开发技术与环…

前端学习笔记 | 响应式网页+Boostrap

一、响应式网页 一套代码适应多端 1、媒体查询media(条件){css} max-width 小于等于max-width生效min-width 【案例】左侧隐藏 因为CSS的层叠性&#xff0c;书写顺序&#xff1a;max-width从大到小&#xff1b;min-width从小到大。 【媒体查询完整写法】 在html中link用于不同…

JSP和JSTL板块:第二节 JSP的指令和动作 来自【汤米尼克的JAVAEE全套教程专栏】

JSP和JSTL板块&#xff1a;第二节 JSP的指令和动作 一、page指令&#xff1a;页面设置&#xff08;1&#xff09;导入包&#xff1a;import属性&#xff08;2&#xff09;设定字符集&#xff1a;pageEncoding属性&#xff08;3&#xff09;设定错误页面&#xff1a;errorPage/i…

Docker上安装配置tomcat

目录 1. 拉取镜像 2. 创建运行镜像 3. 查看是否创建成功 ps&#xff1a;如果出现404错误 tomcat目录结构 1. 拉取镜像 这里使用 tomcat:8.5.40 版本作为安装 docker pull tomcat:8.5.40 2. 创建运行镜像 docker run -d --name tomcat -p 8080:8080 \--privilegedtrue …

day07-CSS高级

01-定位 作用&#xff1a;灵活的改变盒子在网页中的位置 实现&#xff1a; 1.定位模式&#xff1a;position 2.边偏移&#xff1a;设置盒子的位置 left right top bottom 相对定位 position: relative 特点&#xff1a; 不脱标&#xff0c;占用自己原来位置 显示模…

题目:有1,2,3,4共四个数字,能组成多少个不相同而且无重复数字的三位数有多少个,都是多少?lua

这是作者的思路&#xff0c; 创建三个表&#xff0c; 第一个数是从四个数遍历&#xff0c; 第二个是数剔除第一个数进行遍历 第三个是剔除第一第二个数遍历 脚本如下 local a{1,2, 3, 4} local b{} local c{} local d{} local function copy(tbl) local ctbl{} for k,v in…

【JS】基于node-media-server搭建流媒体服务器示例

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍基于node-media-server搭建流媒体服务器示例。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

【机器学习】常见算法详解第2篇:KNN之kd树介绍(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论机器学习算法相关知识。机器学习算法文章笔记以算法、案例为驱动的学习&#xff0c;伴随浅显易懂的数学知识&#xff0c;让大家掌握机器学习常见算法原理&#xff0c;应用Scikit-learn实现机器学习算法的应用&#xff0…

Windows Server安装部署FTP服务

文章目录 建立FTP目录通过IIS在Server上安装FTP服务配置FTP站点配置身份验证和授权测试FTP服务FTP软件推荐FTP客户端软件FTP服务器软件适合Ubuntu的FTP软件 推荐阅读 在Windows操作系统中安装和配置FTP服务&#xff0c;主要是基于Internet Information Services (IIS)的FTP服务…

ABAP 笔记--内表结构不一致,无法更新数据库MODIFY和UPDATE

目录 ABAP 笔记内表结构不一致&#xff0c;无法更新数据库MODIFY和UPDATE ABAP 笔记 内表结构不一致&#xff0c;无法更新数据库 MODIFY和UPDATE 如果是使用MODIFY或者UPDATE

【2024.2.3练习】修剪灌木

题目描述 题目分析 数学思维题。首先容易看出从左往右树的最大高度是对称的&#xff0c;不妨只看前棵树&#xff0c;由于此时右边的灌木数量不少于左边灌木数量&#xff0c;所以要想长到最高一定是修剪到最右边再剪回来&#xff0c;设该树右边共有棵树&#xff0c;那么它能长到…

python基于django的公交线路查询系统mf383

1.个人信息的管理&#xff1a;对用户名&#xff0c;密码的增加、删除等 2.线路信息的管理&#xff1a;对线路的增加、修改、删除等 3.站点信息的管理&#xff1a;对站点的增加、修改、删除等 4.车次信息的管理&#xff1a;对车次的增加、修改、删除等 5.线路查询、站点查询 …

JAVASE进阶:Collection高级(1)——源码分析contains方法、lambda遍历集合

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;JAVASE进阶&#xff1a;函数式编程——lambda表达式替代匿名内部类 &#x1f4da;订阅专栏&#xff1a;JAVASE进阶 希望文章对你…