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

【LeetCode215】数组中的第K个最大元素

题目地址

1. 基本思路

用一个基准数e将集合S分解为不包含e在内的两个小集合 S 1 S_{1} S1 S 2 S_{2} S2,其中 S 1 S_{1} S1的任何元素均大于等于e, S 2 S_{2} S2的任何元素均小于e,记 ∣ S ∣ |S| S代表集合S元素的个数,这样,如果 ∣ S 1 ∣ ≥ K |S_{1}|\ge K S1K,则说明第K大数在 S 1 S_{1} S1中;如果 ∣ S 1 ∣ |S_{1}| S1恰好等于K-1,说明e是第K大数;否则第K大数在 S 2 S_{2} S2中,并且是 S 2 S_{2} S2中的第 K − ∣ S 1 ∣ − 1 K-|S_{1}|-1 KS11大数。然后,可以用类似的思路继续在 S 1 S_{1} S1 S 2 S_{2} S2中查找。
其实这就是快速排序划分数组的过程

2. 最后一个巨型测试用例不通过的代码

//求划分
//其实这个方法就是快速排序求划分的过程
int divide(int* nums, int left, int right)
{//基准数e选nums[left],题目中的数组非空,不用判断特殊情况int e = nums[left];//接下来要把数组分成两部分,一部分小于e,一部分大于等于ewhile (left < right){//让right一直向左移动,直到找到比基准数e小的数,并让这个元素传入left的位置while (left < right && nums[right] >= e){right--;}nums[left] = nums[right];//让left一直向右移动,直到找到比基准数e大的数,并让这个元素传入right的位置while (left < right && nums[left] <= e){left++;}nums[right] = nums[left];}nums[left] = e; //基准数最终存放的位置return left; //返回基准数的新下标
}
//递归用的helper
int findKthLargestHelper(int* nums, int left, int right, int k)
{// 数组S1的元素都大于等于基准数e,但是S1不包括基准数e,先求出基准数的下标e_index// 数组S2就是0到S1_start - 1这些下标对应的元素int e_index = divide(nums, left, right);// 求出S1的长度(注意,S1不包括基准数e),right - e_index - 1 + 1即right - e_indexint len_S1 = right - e_index;// 如果S1长度大于kif (len_S1 >= k){//S1和S2都不包括基准数ereturn findKthLargestHelper(nums, e_index + 1, right, k);}else if (len_S1 < k - 1){return findKthLargestHelper(nums, left, e_index - 1, k - len_S1 - 1);}else //恰好S1长度为k-1,说明基准数是第k大的数{return nums[e_index];}
}
int findKthLargest(int* nums, int numsSize, int k) {//如果使用递归,最后一个巨大的测试用例无法通过,故使用循环int left = 0;int right = numsSize - 1;// 数组S1的元素都大于等于基准数e,但是S1不包括基准数e,先求出基准数的下标e_index// 数组S2就是0到S1_start - 1这些下标对应的元素int e_index = 0; //先初始化为0// 求出S1的长度(注意,S1不包括基准数e),right - e_index - 1 + 1即right - e_indexint len_S1 = 0; //先初始化为0while(left <= right){e_index = divide(nums, left, right);len_S1 = right - e_index;// 如果S1长度大于kif (len_S1 >= k){//就继续去S1数组中继续分割left = e_index + 1;//k值不变}else if (len_S1 < k - 1){//去S2数组中继续分割right = e_index - 1;//k值变化k = k - len_S1 - 1;}else{//恰好S1长度为k-1,说明基准数是第k大的数return nums[e_index];}}return nums[e_index];
}

正好卡在最后一个测试用例:

没通过的原因是,我们取的基准值不是从数组中选的随机值,接下来修改代码

3. 选用随机值的快速排序划分

//生成从x到y的整数随机数
int getIntRandom(int x, int y)
{// 传入时间戳,生成伪随机数srand((unsigned int)time(NULL));return (int)(x + (rand() % (y - x + 1)));
}
//求划分
//其实这个方法就是快速排序求划分的过程
int divide(int* nums, int left, int right)
{//随机选一个基准数的下标int random_index = getIntRandom(left, right);// 基准值int e = nums[random_index];// 将nums[random_index]和nums[left]互换,方便后来交换int temp = nums[random_index];nums[random_index] = nums[left];nums[left] = temp;//接下来要把数组分成两部分,一部分小于e,一部分大于等于ewhile (left < right){//让right一直向左移动,直到找到比基准数e小的数,并让这个元素传入left的位置while (left < right && nums[right] >= e){right--;}nums[left] = nums[right];//让left一直向右移动,直到找到比基准数e大的数,并让这个元素传入right的位置while (left < right && nums[left] <= e){left++;}nums[right] = nums[left];}nums[left] = e; //基准数最终存放的位置return left; //返回基准数的新下标
}
//递归用的helper
int findKthLargestHelper(int* nums, int left, int right, int k)
{// 数组S1的元素都大于等于基准数e,但是S1不包括基准数e,先求出基准数的下标e_index// 数组S2就是0到S1_start - 1这些下标对应的元素int e_index = divide(nums, left, right);// 求出S1的长度(注意,S1不包括基准数e),right - e_index - 1 + 1即right - e_indexint len_S1 = right - e_index;// 如果S1长度大于kif (len_S1 >= k){//S1和S2都不包括基准数ereturn findKthLargestHelper(nums, e_index + 1, right, k);}else if (len_S1 < k - 1){return findKthLargestHelper(nums, left, e_index - 1, k - len_S1 - 1);}else //恰好S1长度为k-1,说明基准数是第k大的数{return nums[e_index];}
}
int findKthLargest(int* nums, int numsSize, int k) {//如果使用递归,最后一个巨大的测试用例无法通过,故使用循环int left = 0;int right = numsSize - 1;// 数组S1的元素都大于等于基准数e,但是S1不包括基准数e,先求出基准数的下标e_index// 数组S2就是0到S1_start - 1这些下标对应的元素int e_index = 0; //先初始化为0// 求出S1的长度(注意,S1不包括基准数e),right - e_index - 1 + 1即right - e_indexint len_S1 = 0; //先初始化为0while(left <= right){e_index = divide(nums, left, right);len_S1 = right - e_index;// 如果S1长度大于kif (len_S1 >= k){//就继续去S1数组中继续分割left = e_index + 1;//k值不变}else if (len_S1 < k - 1){//去S2数组中继续分割right = e_index - 1;//k值变化k = k - len_S1 - 1;}else{//恰好S1长度为k-1,说明基准数是第k大的数return nums[e_index];}}return nums[e_index];
}

提交结果:

相关文章:

  • 爆赞!GitHub首本Python开发实战背记手册,标星果然百万名不虚传
  • Ant-Design-Vue动态表头并填充数据
  • vue3写一个定时器
  • Kantana和The Sandbox联手打造元宇宙娱乐的未来
  • Android开启HTTP服务
  • 微服务必备容器化技术
  • LUA移植到STM32F4,移植REPL,通过RTT Viewer交互
  • GraogGNSSLib学习
  • 医学人工智能在“免疫组化”领域的最新研究进展|顶刊速递·24-06-19
  • 美业人专用宝藏系统、Java收银系统源码分享-美业SAAS系统的应用价值分析
  • 关于INCA的几个实用功能
  • Top10在线音频剪辑软件,你了解几款?(免费分享)
  • 前端技术回顾系列 11|TS 中一些实用概念
  • Android C++系列:函数知识知多少
  • Linux时间子系统7:sleep timer接口定时实现
  • 10个最佳ES6特性 ES7与ES8的特性
  • AWS实战 - 利用IAM对S3做访问控制
  • co.js - 让异步代码同步化
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • express + mock 让前后台并行开发
  • HashMap ConcurrentHashMap
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • Laravel 菜鸟晋级之路
  • NSTimer学习笔记
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Python打包系统简单入门
  • SAP云平台里Global Account和Sub Account的关系
  • SpringCloud(第 039 篇)链接Mysql数据库,通过JpaRepository编写数据库访问
  • 基于 Babel 的 npm 包最小化设置
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​经​纬​恒​润​二​面​​三​七​互​娱​一​面​​元​象​二​面​
  • #13 yum、编译安装与sed命令的使用
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • (55)MOS管专题--->(10)MOS管的封装
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (三)模仿学习-Action数据的模仿
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (一)RocketMQ初步认识
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (原創) 未来三学期想要修的课 (日記)
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • ****Linux下Mysql的安装和配置
  • *2 echo、printf、mkdir命令的应用
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • *p++,*(p++),*++p,(*p)++区别?
  • .NET COER+CONSUL微服务项目在CENTOS环境下的部署实践