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

堆----1.数组中的第K个最大元素

215. 数组中的第K个最大元素 - 力扣(LeetCode)

/**

        第一大元素--->len - 1

        第二大元素--->len - 2

        .......

        第K大元素---->len - K,则数组中第K个最大元素,转化为寻找排序后第len - K位置的元素

        快速选择算法:

                    快速排序的变种,核心的分区函数一致,在数组中随机选择一个基准 pivot

                    按基准将数组划分为三个部分 小于基准 基准 大于基准,那么此时基准所在的位置就是排序后该在的位置

                变种:

                    在本题中,若划分后基准所在位置恰好是len - k,那么说明基准就是第K个最大元素

                    若基准 < len - K, 则减小范围,在[基准 + 1,right]中重新选择基准,重复上述流程

                    若基准 > len - K, 则减小范围,在[left, 基准 - 1]中重新选择基准,重复上述流程

                    直到找到为止

                分区函数(核心):

                    首先在数组中随机选择一个元素为基准元素,从左右两端同时开始扫描

                    左指针向右遍历,直到遇到第一个>=pivot的元素

                    右指针向左遍历,直到遇到第一个<=pivot的元素

                    交换左右指针的值,交换后,大于基准元素的在右半区,小于基准元素的在左半区,等于基准元素的平均分布在左、右半区

                细节注意:

                    在选择出基准元素后,将其移至数组首位

                    遍历完毕后基准元素与左指针交换位置,将基准元素移动至正确位置

 */

class Solution {/**第一大元素--->len - 1第二大元素--->len - 2.......第K大元素---->len - K,则数组中第K个最大元素,转化为寻找排序后第len - K位置的元素快速选择算法:快速排序的变种,核心的分区函数一致,在数组中随机选择一个基准 pivot按基准将数组划分为三个部分 小于基准 基准 大于基准,那么此时基准所在的位置就是排序后该在的位置变种:在本题中,若划分后基准所在位置恰好是len - k,那么说明基准就是第K个最大元素若基准 < len - K, 则减小范围,在[基准 + 1,right]中重新选择基准,重复上述流程若基准 > len - K, 则减小范围,在[left, 基准 - 1]中重新选择基准,重复上述流程直到找到为止分区函数(核心):首先在数组中随机选择一个元素为基准元素,从左右两端同时开始扫描左指针向右遍历,直到遇到第一个>=pivot的元素右指针向左遍历,直到遇到第一个<=pivot的元素交换左右指针的值,交换后,大于基准元素的在右半区,小于基准元素的在左半区,等于基准元素的平均分布在左、右半区细节注意:在选择出基准元素后,将其移至数组首位遍历完毕后基准元素与左指针交换位置,将基准元素移动至正确位置*/private int[] nums;private int target;private final Random random = new Random();public int findKthLargest(int[] nums, int k) {this.nums = nums;this.target = nums.length - k;quickSelect(0,nums.length - 1);return nums[target];}//快速选择private void quickSelect(int left, int right) {if(left > right) {return;}int pivotIndex = partition(left, right); //得到第一个有序的位置if(pivotIndex == target) { return;} else if(pivotIndex < target) {quickSelect(pivotIndex + 1, right); //[基准 + 1,right]} else {quickSelect(left,pivotIndex - 1); //[left, 基准 - 1]}}//分区函数private int partition(int left, int right) {//生成随机基准int pivot = random.nextInt(right - left + 1) + left;int pivotValue = nums[pivot];swap(left,pivot); //先将基准移至首位//双端同时开始扫描int le = left + 1;int ge = right;while(true) {//左指针向右遍历,直到遇到第一个>=pivot的元素while(le <= ge && nums[le] <pivotValue) {le++;}//右指针向左遍历,直到遇到第一个<=pivot的元素while(le <= ge && nums[ge] > pivotValue) {ge--;}//遍历结束退出if(le >= ge) {break;}//交换两指针的值,进行分区swap(le,ge);le++;ge--;}//遍历完毕后基准元素与左指针交换位置,将基准元素移动至正确位置swap(left,ge);return ge;}private void swap(int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}

http://www.lryc.cn/news/608504.html

相关文章:

  • 高效游戏状态管理:使用双模式位运算与数学运算
  • 关于人工智能AI>ML>DL>transformer及NLP的关系
  • springboot大学生成绩管理系统设计与实现
  • NCV8402ASTT1G自保护N沟道功率MOSFET安森美/ONSEMI 过流过温保护汽车级驱动NCV8402ASTT1
  • 动态规划经典模型:双数组问题的通用解决框架与实战
  • Vue3核心语法进阶(computed与监听)
  • 衡石科技实时指标引擎解析:如何实现毫秒级响应万亿级数据的增量计算?
  • 【c#窗体荔枝计算乘法,两数相乘】2022-10-6
  • 【学习笔记】Java并发编程的艺术——第1章 并发编程的挑战
  • Python打卡Day30 模块和库的导入
  • 12:java学习笔记:多维数组1
  • 如何分析Linux内存性能问题
  • 深度学习(鱼书)day09--与学习相关的技巧(前三节)
  • 2025牛客暑期多校训练营1(G,E,L,K,I)
  • 力扣 hot100 Day63
  • 使用 BERT 的 NSP 实现语义感知切片 —— 提升 RAG 系统的检索质量
  • Java试题-选择题(6)
  • 滚珠花键在汽车制造中有哪些高要求?
  • 记录一次Spring Cloud Gateway配置的跨域处理:解决 ‘Access-Control-Allow-Origin‘ 头包含多个值的问题
  • JavaScript将String转为base64 笔记250802
  • GCC(GNU Compiler Collection)与人工智能实例
  • 【前端:Html】--1.1.基础语法
  • [Linux入门] Ubuntu 系统中 iptables 的配置与使用
  • 公共卫生场景下漏检率↓76%:陌讯动态特征融合算法在口罩识别中的实战解析
  • GaussDB having 的用法
  • 适 配 器 模 式
  • 电力系统分析笔记:发电机与变压器的数学建模与运行状态详解
  • SPI通信中CS片选的两种实现方案:硬件片选与软件片选
  • Anthropic:跨越生产效能拐点的AI增长飞轮
  • Munge 安全认证和授权服务的工作原理,以及与 Slurm 的配合