【高频面试题】数组中的第K个最大元素(堆、快排进阶)
文章目录
- 数组中的第K个最大元素
- 题目描述
- 示例1
- 示例2
- 提示:
- 解法1(堆维护前k大元素)
- 解法2 手写堆维护
- 解法3(快速选择算法)
- 例题:P1923 【深基9.例4】求第 k 小的数
- 参考
数组中的第K个最大元素
题目描述
给定整数数组 n u m s nums nums和整数 k k k,请返回数组中第 k k k 个最大的元素。
请注意,你需要找的是数组排序后的第 k k k 个最大的元素,而不是第 k k k 个不同的元素。
你必须设计并实现时间复杂度为 O ( n ) O(n) O(n)的算法解决此问题。
示例1
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例2
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
提示:
- 1 < = k < = n u m s . l e n g t h < = 10 5 1 <= k <= nums.length <= 10^5 1<=k<=nums.length<=105
- − 10 4 < = n u m s [ i ] < = 10 4 -10^4 <= nums[i] <= 10^4 −104<=nums[i]<=104
解法1(堆维护前k大元素)
时间复杂度 O ( n l o g k ) O(nlogk) O(nlogk) 空间复杂度 O ( k ) O(k) O(k)
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int, vector<int>, greater<int>> pq; for(auto& num: nums){pq.emplace(num);if(pq.size() > k){pq.pop(); // 堆中元素超过k个,弹出最小的那个}}return pq.top(); }
};
解法2 手写堆维护
思路:
- n u m s nums nums种存放二叉堆,索引 [ 0 , n − 1 ] [0,n - 1] [0,n−1]对应按层序遍历对应的元素,对于下标从0开始的某节点 i i i,左右孩子节点编号分别为 i ∗ 2 + 1 , i ∗ 2 + 2 i*2+1,i*2+2 i∗2+1,i∗2+2
- 下沉操作: m a x H e a p i f y maxHeapify maxHeapify操作为将二叉堆数组 n u m s nums nums索引 i i i处元素下沉
- 建堆操作:我们从最后一个非叶子节点 h e a p S i z e / 2 − 1 heapSize / 2-1 heapSize/2−1开始倒序遍历,从下往上下沉
- 删除操作:每次将堆顶交换到数组末尾,再将 h e a p S i z e heapSize heapSize减一,最后再调整新的堆顶即可
- 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn) 空间复杂度 O ( l o g n ) O(logn) O(logn) 因为最大堆需要维护n个结点
class Solution {
public:// down void maxHeapify(vector<int>& a, int i, int heapSize) {int l = i * 2 + 1, r = i * 2 + 2, largest = i;if (l < heapSize && a[l] > a[largest]) {largest = l;}if (r < heapSize && a[r] > a[largest]) {largest = r;}if (largest != i) {swap(a[i], a[largest]);maxHeapify(a, largest, heapSize);}}// initialize void buildMaxHeap(vector<int>& a, int heapSize) {for (int i = heapSize / 2 - 1; i >= 0; i--) {maxHeapify(a, i, heapSize);}}int findKthLargest(vector<int>& nums, int k) {int heapSize = nums.size();buildMaxHeap(nums, heapSize); // 建堆// 执行k-1次提取最大值操作for (int i = nums.size() - 1; i >= nums.size() - k + 1; i--) {swap(nums[0], nums[i]); // 调整堆顶-- heapSize; // 删除堆maxHeapify(nums, 0, heapSize); }return nums[0];}
};
解法3(快速选择算法)
我们首先来回顾一下快排的实现
void quickSort(vector<int>& nums, int l, int r) {if (l >= r) return;// - i 初始在左边界左侧(l-1)// - j 初始在右边界右侧(r+1)// - 基准值 x 选中间元素(避免极端情况如全排序数组导致最坏时间复杂度)int i = l - 1, j = r + 1;int x = nums[(l + r) >> 1]; // 位运算代替 (l + r) / 2,等价且更高效// partition :双指针从两端向中间移动while (i < j) {// 移动左指针 i:跳过所有小于 x 的元素,直到找到 >=x 的元素do i++; while (nums[i] < x); // 移动右指针 j:跳过所有大于 x 的元素,直到找到 <=x 的元素do j--; while (nums[j] > x);// 如果指针未交错,交换左右指针的元素(确保左边 <=x,右边 >=x)if (i < j) swap(nums[i], nums[j]);}// 4. 递归排序左右子数组:quickSort(nums, l, j), quickSort(nums, j + 1, r);
}
- 快速选择( Q u i c k s e l e c t Quickselect Quickselect)算法是一种用于在未排序的列表中找到第k小(或第k大)元素的高效算法。与快速排序一样,它使用分治策略,但不同于快速排序的是,它只递归处理包含目标元素的那一部分,而不是全部。这使得快速选择的平均时间复杂度为 O ( n ) O(n) O(n),最坏情况为 O ( n 2 ) O(n^2) O(n2),但在实际应用中,通过随机化选取枢轴( p i v o t pivot pivot)可以避免最坏情况。
- 复杂度:递归时,每层时间复杂度为 O ( n ) O(n) O(n),但并不是都进入左右两部分递归。仅进入一侧递归在平均情况下 数组长度会减半,故平均情况下的时间复杂度为 n + n / 2 + n / 4 + … + 1 = O ( n ) n+n/2+n/4+…+1=O(n) n+n/2+n/4+…+1=O(n)
以下是快速选择实现找第K大元素的具体实现:
class Solution {
public:int quick_select(vector<int>& nums, int l, int r, int k) {if (l == r) return nums[k];int i = l - 1, j = r + 1, x = nums[l + r >> 1]; // 若选取nums[l], 极端样例 时间会很久//int x = nums[rand() % (r - l + 1) + l], i = l - 1, j = r + 1; // 随机选取while (i < j) {do i ++ ; while (nums[i] > x); // 注意是第k大 上面的模板是升序排序do j -- ; while (nums[j] < x);if (i < j) swap(nums[i], nums[j]);}if (k <= j) return quick_select(nums, l, j, k);else return quick_select(nums, j + 1, r, k);}int findKthLargest(vector<int>& nums, int k) {//srand(time(0)); // 随机种子return quick_select(nums, 0, nums.size() - 1, k - 1); // 0-base}
};
例题:P1923 【深基9.例4】求第 k 小的数
#include <bits/stdc++.h>using namespace std;const int N = 5e6 + 7;int n, k;
int a[N];int quick_select(int nums[], int l, int r, int k) {if (l == r) return nums[k];int x = nums[l], i = l - 1, j = r + 1;while (i < j) {// paration 方向改一下即可do i ++; while (nums[i] < x); do j --; while (nums[j] > x);if (i < j) swap(nums[i], nums[j]);}if (k <= j) return quick_select(nums, l, j, k);else return quick_select(nums, j + 1, r, k);
}int main() {scanf("%d%d", &n, &k);//getchar();for (int i = 0; i < n; i++) {scanf("%d", &a[i]);}printf("%d\n", quick_select(a, 0, n - 1, k));return 0;
}
参考
- LeetCode官方题解:数组中的第K个最大元素
- yxc常用代码模板1——基础算法
- LeetCode 215. 数组中的第K个最大元素
相关文章:
【高频面试题】数组中的第K个最大元素(堆、快排进阶)
文章目录 数组中的第K个最大元素题目描述示例1示例2提示: 解法1(堆维护前k大元素)解法2 手写堆维护解法3(快速选择算法)例题:P1923 【深基9.例4】求第 k 小的数参考 数组中的第K个最大元素 题目描述 给定…...
Java互联网大厂面试:从Spring Boot到Kafka的技术深度探索
Java互联网大厂面试:从Spring Boot到Kafka的技术深度探索 在某家互联网大厂的面试中,面试官A是一位技术老兵,而被面试者谢飞机,号称有丰富的Java开发经验。以下是他们的面试情景: 场景:电商平台的后端开发…...
基于Python的单斜式ADC建模与仿真分析
基于Python的单斜式ADC建模与仿真分析 1 引言 CMOS图像传感器的读出电路中,列级ADC因其面积效率高(每列共享ADC)、功耗低(并行工作降低频率需求)和固定模式噪声小(结构对称性高)等优势成为大像素阵列的首选方案。本文针对50KS/s采样率、10位分辨率的单斜式ADC进行系统…...
笔记本电脑右下角wifi不显示,连不上网怎么办?
解决思路:设备管理器--先禁用wifi6硬件-再启用wifi6硬件(20秒搞定) 笔记本电脑右下角的wifi经常莫名其妙的不显示,连不上网,感觉应该是与什么程序不兼容,导致wifi模块被办掉了,怎么这种情况出现…...

一篇文章玩转CAP原理
CAP 原理是分布式系统设计的核心理论之一,揭示了系统设计中的 根本性权衡。 一、CAP 的定义 CAP 由三个核心属性组成,任何分布式系统最多只能同时满足其中两个: 一致性(Consistency) 所有节点在同一时刻看到的数据完全…...

Vue-收集表单信息
收集表单信息 Input label for 和 input id 关联, 点击账号标签 也能聚焦 input 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>表单数据</title><!-- 引入Vue --><scrip…...
私服 nexus 之间迁移 npm 仓库
本文介绍如何将一个 Nexus 特定仓库中的 npm 包内容迁移到另一个 Nexus 特定仓库。此过程适用于需要重构仓库结构或合并仓库的场景。 迁移脚本 以下是完整的迁移脚本,它会自动完成以下操作: 从源仓库获取所有 npm 包列表下载每个包的 .tgz 文件解压并…...
微服务及容器化设计--可扩展的架构设计
引言 在当今快速发展的技术环境中,企业需要构建能够适应变化、支持快速迭代且可靠的软件系统。传统的单体应用架构在面对高并发、大规模部署和复杂业务逻辑时往往力不从心。微服务架构结合容器化技术应运而生,成为现代可扩展系统设计的主流选择。本文将…...

vscode开发stm32,main.c文件中出现很多报错影响开发解决日志
本质上为 .vscode/c_cpp_properties.json文件和Makefile文件中冲突,两者没有同步。 将makefile文件中的内容同步过来即可,下面给出一个json文件的模板,每个人的情况不同,针对性修改即可 {"configurations": [{"na…...

嵌入式鸿蒙系统中水平和垂直以及图片调用方法
利用openharmony操作的具体现象: 第一:Column 作用:沿垂直方向布局的容器。 第二:常用接口 Column(value?: {space?: string | number}) 参数: 参数名参数类型必填参数描述spacestring | number否纵向布局元素垂直方向间距。 从API version 9开始,space为负数或者ju…...

【海康USB相机被HALCON助手连接过后,MVS显示无法连接故障。】
在Halcon里使用助手调用海康USB相机时,如果这个界面点击了【是】 那么恭喜你,相机只能被HALCON调用使用,使用MVS或者海康开发库,将查找不到相机 解决方式: 右键桌面【此电脑】图标 ->选择【管理】 ->选择【设备…...
面试大厂Java:从Spring Boot到微服务架构
面试大厂Java:从Spring Boot到微服务架构 在一个阳光明媚的下午,谢飞机来到了某知名互联网大厂的面试现场,迎接他的是一位严肃的面试官。 第一轮提问: 面试官: 谢飞机,请你简单介绍一下Spring Boot的核心…...

2025年电气工程与轨道交通国际会议:绿色能源与智能交通的创新之路
2025年电气工程与轨道交通国际会议(ICEERT 2025)是一场电气工程与轨道交通领域的国际盛会,将于2025年在武汉隆重召开。此次会议汇聚了全球顶尖的专家学者和行业精英,共同探讨电气工程与轨道交通的最新研究成果和技术趋势。会议将围…...
macOS 安装 Grafana + Prometheus + Node Exporter
macOS 安装指南:Grafana Prometheus Node Exporter 目录简介🚀 快速开始 安装 Homebrew1. 安装 Homebrew2. 更新 Homebrew 安装 Node Exporter使用 Homebrew 安装验证 Node Exporter 安装 Prometheus使用 Homebrew 安装验证安装 安装 Grafana使用 Home…...

WPF log4net用法
WPF log4net用法 一、在工程中管理NuGet程序包,找到log4net,点击安装,如下图已成功安装; 二、在工程中右键添加新建项,选择应用程序配置文件(后缀为.config),然后设置名称,这里设置…...

数字孪生数据监控如何提升汽车零部件工厂产品质量
一、汽车零部件工厂的质量挑战 汽车零部件作为汽车制造的基础,其质量直接关系到整车的性能、可靠性和安全性。在传统的汽车零部件生产过程中,质量问题往往难以在早期阶段被发现和解决,导致生产效率低下、生产成本上升,甚至影响到…...
web自动化-Selenium、Playwright、Robot Framework等自动化框架使用场景优劣对比
Web 自动化测试框架根据不同的技术栈和应用场景可分为多种类型,以下是常见的框架及其特点、适用场景: 一、主流框架分类 1. Selenium 生态(Python/Java/C#/JavaScript) 核心组件: WebDriver:操作浏览器的…...
使用 Akamai 分布式云与 CDN 保障视频供稿传输安全
作者简介:David Eisenbacher 是 EZDRM 公司的首席执行官兼联合创始人,该公司是首家提供 "DRM 即服务" 的企业。作为 CEO,David 始终秉持为企业确立的使命:为视频服务商提供简洁有效的数字版权管理方案,助力其…...
vue发版html 生成打包到docker镜像进行发版
将Vue项目打包成Docker镜像部署主要分为以下几个步骤: 1. Vue项目打包 执行npm run build生成dist文件夹,包含静态资源文件 注意检查index.html中资源引用路径是否正确(避免绝对路径问题) 2. 编写Dockerfile Copy Code FROM…...
python uv包管理器使用
官方文档:uv官方文档 注:uv安装不依赖python。 使用: python版本管理 # 查看已安装的python列表 uv python list # 安装特定版本 uv python install 3.12 # 指定项目使用的python版本 uv python pin <version># 使用指定版本运行脚本…...

贪心算法实战3
文章目录 前言区间问题跳跃游戏跳跃游戏II用最少数量的箭引爆气球无重叠区间划分字母区间合并区间 最大子序和加油站监控二叉树 前言 今天继续带大家进行贪心算法的实战篇3,本章注意来解答一些运用贪心算法的比较难的问题,大家好好体会,怎么…...
linux、docker、git相关操作
1 linux 1.1解压缩 1.1.1 zip zip xxx.zip file 把file压缩成xxx.zip -r 递归压缩: zip -r example_new.zip 示例集 # 新建压缩包并命名为 example_new.zip zip -r xxx.zip file1 file2 dir1 将多个文件目录压成zip包 unzip file.zip -d target_dir #把file.zip解…...

实测,大模型谁更懂数据可视化?
大家好,我是 Ai 学习的老章 看论文时,经常看到漂亮的图表,很多不知道是用什么工具绘制的,或者很想复刻类似图表。 实测,大模型 LaTeX 公式识别,出乎预料 前文,我用 Kimi、Qwen-3-235B-A22B、…...
小程序32-简易双向数据绑定
在WXML中,普通属性的绑定是单向的,例如:<input value"{{value}}" /> 如果希望用户输入数据的同时改变data中的数据,可以借助简易双向绑定机制。在对应属性之前添加model:前缀即可: 例如<input model:value"{{value}…...
jenkins报错java.lang.OutOfMemoryError: Java heap space
报错信息 2025-05-27 09:17:16.2340000 [id38] WARNING j.u.ErrorLoggingScheduledThreadPoolExecutor#afterExecute: failure in task not wrapped in SafeTimerTask java.lang.OutOfMemoryError: Java heap spaceat java.base/java.lang.StringUTF16.compress(StringUTF16.j…...
leetcode669.修剪二叉搜索树:递归法利用有序性精准剪枝
一、题目深度解析与BST特性应用 题目描述 给定一棵二叉搜索树(BST)和一个值区间[low, high],修剪BST使得所有节点的值都落在该区间内。修剪后的树必须保持BST的性质,且不能改变原有节点的相对位置关系。 BST的核心特性应用 二…...
Spring Boot 中 @RequestParam 和 @RequestPart 的区别详解(含实际项目案例)
Spring Boot 中 RequestParam 和 RequestPart 的区别详解(含实际项目案例) 在日常的 Spring Boot 开发中,我们经常会遇到表单提交、文件上传、JSON 参数绑定等需求。而在处理这类请求时,两个常见的注解——RequestParam 和 Reque…...

Linux入门(十一)进程管理
Linux 中每个执行的程序都称为一个进程,每个进程都分配一个ID号(PID) 每个进程都可能以两种方式存在,前台(屏幕上可以操作的)和后台(屏幕上无法看到的),一般系统的服务都…...
【课堂笔记】EM算法
文章目录 背景极大似然估计隐变量高斯混合模型EM算法合理性分析相关好文章背景 EM算法(期望最大化算法,Expectation-Maximization Algorithm)是一种迭代优化算法,用于在含有隐变量的概率模型中估计最大似然参数。 这是概括性的定义,下面我会解释其中的名词并用具体例子…...
怎样将win11+ubuntu双系统的ubuntu从机械硬盘迁移至固态硬盘(1)
将 Ubuntu 从机械硬盘迁移到固态硬盘是一个涉及多个步骤的过程。以下是一个基本的迁移指南: 1. 前期准备 1.1 备份数据: 确保你已备份数据,以防止在迁移过程中出现意外导致任何数据丢失。 1.2 固态硬盘安装: 确保固态硬盘正确…...