当前位置: 首页 > news >正文

「数组」随机快速选择 / LeetCode LCR 076(C++)

前置知识

在本篇文章之前,你应该先掌握快速排序的基本技巧,详见:「数组」快速排序 / 随机值优化|小区间插入优化(C++)

概述 

LeetCode LCR 076是这么一道题:

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

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

示例 :

输入: [3,2,1,5,6,4] 和 k = 2输出: 5

这样的题目可以直接通过快速选择进行完全排序,但时间复杂度是O(nlogn)。如果我们要求必须在O(n)时间内得到结果呢?随机数优化的快速排序变体:随机快速选择能完成这个工作。 

思路

在快速选择中,我们不得不进行全部的递归与回溯过程来实现数组的完全排序。

但是在只要求某个元素位置正确时,我们注意到:

void quick_sort(int arr[], int l,int r) {if (r-l<=1)return ;int pos = partition(arr, l, r);quick_sort(arr, l, pos);quick_sort(arr, pos + 1, r);
}

两个子区间排序的其中一个是不必要的,并且如果已经安放了正确的元素位置,以后的所有递归都是不必要的。

算法过程 

那么快速选择过程就可以进行对应的优化。

这就意味着:

①我们只需要判断parition分区函数返回的pos与期望位置之间的关系,并转发给对应的子排序

②当got_ans==true时,我们可以直接返回来实现剪枝。

void quick_select(vector<int>& nums,int l,int r,int& k,const int& len,bool& got_ans){if(r-l<1||got_ans)return ;int pos=partition(nums,l,r);if(pos==len-k){got_ans=true;return;}if(pos>len-k)quick_select(nums,l,pos,k,len,got_ans);if(pos<len-k)quick_select(nums,pos+1,r,k,len,got_ans);}

partition函数仍然保持原状:

int partition(vector<int>& nums,int l,int r){int pivot=l+mt()%(r-l);swap(nums[pivot],nums[r-1]);int i,j;for(i=l,j=l;j<r;j++)if(nums[j]<=nums[r-1])swap(nums[i++],nums[j]);return i-1;}

 由于此算法是随机快速排序的特化体,故为随机快速选择。

复杂度

时间复杂度:O(n)

空间复杂度:O(logn)

复杂度分析: 

时间分析:

在理想情况下,每次都转发给了排序范围折半的子函数。

总用时为T(n),两个T(n/2)为下一级的总时间,n为本次分区所用时间,

T(n)=T(n/2)+n

          =T(n/4)+n/2+n

          ...

          =T(1)+n(1-1/2^n)/(1-1/2)

          =1+2n+n/2^(n-1)

省去小量,得到O(n)


空间分析:

与快速排序相同,每一级子函数都使用了常量空间,因此空间复杂度是logn级别的。

Code

class Solution {
private:mt19937 mt;
public:int partition(vector<int>& nums,int l,int r){int pivot=l+mt()%(r-l);swap(nums[pivot],nums[r-1]);int i,j;for(i=l,j=l;j<r;j++)if(nums[j]<=nums[r-1])swap(nums[i++],nums[j]);return i-1;}void quick_select(vector<int>& nums,int l,int r,int& k,const int& len,bool& got_ans){if(r-l<1||got_ans)return ;int pos=partition(nums,l,r);if(pos==len-k){got_ans=true;return;}if(pos>len-k)quick_select(nums,l,pos,k,len,got_ans);if(pos<len-k)quick_select(nums,pos+1,r,k,len,got_ans);}int findKthLargest(vector<int>& nums, int k) {bool got_ans=false;const int len=nums.size();quick_select(nums,0,len,k,len,got_ans);return nums[len-k];}
};

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • VMWare虚拟机磁盘扩容
  • 【langchain学习】使用LangChain创建具有上下文感知的问答系统
  • 微服务-分布式事务-seata
  • 神经网络:智能时代的基石
  • 再分享API形式调用Dify项目应用
  • 大语言模型生成无人系统(如机械臂、无人机等)可以执行的指令序列
  • 初学嵌入式-C语言常犯错误详解
  • 【机器学习之深度学习】Sigmoid和ReLU的联系与区别、ReLU如何解决死亡问题以及Tanh激活函数的基本概念
  • ClickHouse:单机安装
  • 【数据结构】—— 队列
  • 阿里大模型调用 = 》通义千问大语言模型
  • GenAI下沉到边缘侧,内存和性能如何平衡?
  • 江科大/江协科技 STM32学习笔记P22
  • 四数之和(LeetCode)
  • Linux 系统框架分析(一)
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 2017届校招提前批面试回顾
  • 2019.2.20 c++ 知识梳理
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • docker-consul
  • EOS是什么
  • express如何解决request entity too large问题
  • Linux各目录及每个目录的详细介绍
  • ng6--错误信息小结(持续更新)
  • Spring Boot快速入门(一):Hello Spring Boot
  • springMvc学习笔记(2)
  • Vim 折腾记
  • vue的全局变量和全局拦截请求器
  • 服务器之间,相同帐号,实现免密钥登录
  • 解析带emoji和链接的聊天系统消息
  • 区块链共识机制优缺点对比都是什么
  • 小程序 setData 学问多
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • #includecmath
  • #mysql 8.0 踩坑日记
  • $(function(){})与(function($){....})(jQuery)的区别
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (k8s)Kubernetes本地存储接入
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (十三)Maven插件解析运行机制
  • (一)Docker基本介绍
  • *p++,*(p++),*++p,(*p)++区别?
  • .Mobi域名介绍
  • .Net core 6.0 升8.0
  • .NET CORE Aws S3 使用
  • .NET 设计一套高性能的弱事件机制
  • .Net实现SCrypt Hash加密
  • .NET学习全景图
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @Controller和@RestController的区别?
  • @JsonFormat与@DateTimeFormat注解的使用