当前位置: 首页 > 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.xdnf.cn/news/1229455.html

相关文章:

  • 通过filezilla在局域网下实现高速传输数据
  • 2025-08 安卓开发面试拷打记录(面试题)
  • 【龙泽科技】汽车故障诊断仿真教学软件【风光580】
  • Vue 详情模块 4
  • Python科研数据可视化技术
  • 知识蒸馏 - 基于KL散度的知识蒸馏 HelloWorld 示例
  • 在 AKS 中运行 Azure DevOps 自托管代理-2
  • 线程池的实现
  • 能力显著性向量:验证损失与下游能力的缩放定律
  • k8s使用 RBAC 鉴权
  • 如何在 Ubuntu 24.04 或 22.04 LTS Linux 上安装 Guake 终端应用程序
  • Allegro降版本工具
  • 学习笔记:无锁队列的原理以及c++实现
  • C# 中抽象类、密封类、静态类和接口的区别
  • Qt 信号和槽正常连接返回true,但发送信号后槽函数无响应问题【已解决】
  • WinForm之ListBox 控件
  • Qt 槽函数被执行多次,并且使用Qt::UniqueConnection无效【已解决】
  • 电子电气架构 --- 汽车网络安全概述
  • Java高性能编程实践指南
  • cv弹窗,退款确认弹窗
  • Java中Lambda 表达式的解释
  • 【AI】AIService(基本使用与指令定制)
  • 操作系统:远程过程调用( Remote Procedure Call,RPC)
  • 公网服务器上Nginx或者Openresty如何屏蔽IP直接扫描
  • java中的synchronized关键字​
  • 福彩双色球第2025088期篮球号码分析
  • PyTorch 张量核心操作——比较、排序与数据校验
  • 利用DeepSeek将Rust程序的缓冲输出改写为C语言实现提高输出效率
  • 深入 Go 底层原理(十五):cgo 的工作机制与性能开销
  • 探索:Uniapp 安卓热更新