【Leetcode 热题 100】215. 数组中的第K个最大元素

server/2025/1/17 21:27:10/

问题背景

给定整数数组 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 ≤ k ≤ n u m s . l e n g t h ≤ 1 0 5 1 \le k \le nums.length \le 10 ^ 5 1knums.length105
  • − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10 ^ 4 \le nums[i] \le 10 ^ 4 104nums[i]104

解题过程

经典求第 k k k大,最佳方案是用随机选择算法,时间复杂度大致是 O ( N ) O(N) O(N) 这个量级。
考虑到题目分类在堆,那除了调用 API 快速处理的方法之外,再写一下手撕堆当作练习。
相关详细的介绍,可以参考 随机快排与随机选择 以及 堆排序与堆操作。

具体实现

使用堆 API

class Solution {public int findKthLargest(int[] nums, int k) {Queue<Integer> queue = new PriorityQueue<>();for(int num : nums) {queue.offer(num);}for(int i = 0; i < nums.length - k; i++) {queue.poll();}return queue.peek();}
}

自己实现堆

class Solution {public int findKthLargest(int[] nums, int k) {int n = nums.length;buildHeap(nums);// 注意这里要修正索引while(k - 1 > 0) {swap(nums, 0, --n);downAdjust(nums, 0, n);k--;}return nums[0];}// 交换数组中的两个元素private void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}// 由上而下调整元素private void downAdjust(int[] arr, int cur, int size) {// 数组下标从零开始,当前节点的左孩子下标为 2 * cur + 1int child = 2 * cur + 1;while (child < size) {// 如果当前节点有右孩子,那么比较两个子节点的值确定潜在的交换对象int target = child + 1 < size && arr[child + 1] > arr[child] ? child + 1 : child;// 再与当前节点比较大小target = arr[target] > arr[cur] ? target : cur;// 一旦发现此次操作中无需交换,立即停止流程if (target == cur) {break;}// 交换父子节点swap(arr, target, cur);// 移动工作指针cur = target;child = 2 * cur + 1;}}// 自底向顶建堆private void buildHeap(int[] arr) {int n = arr.length;for (int i = n - 1; i >= 0; i--) {downAdjust(arr, i, n);}}
}

随机选择

class Solution {// 全局变量 first 表示等于当前元素的第一个下标位置,last 表示最后一个private static int first, last;public int findKthLargest(int[] nums, int k) {return randomizedSelect(nums, nums.length - k);}// 交换数组中的两个元素private void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}private void partition(int[] arr, int left, int right, int pivot) {// 初始化维护的指针first = left;last = right;int cur = left;// 注意循环到工作指针超越 last 即可结束流程while (cur <= last) {if (arr[cur] == pivot) {cur++; // 当前元素等于划分标准,不作处理并后移指针} else if (arr[cur] < pivot) {swap(arr, first++, cur++); // 小于划分标准,交换且分别后移两个指针} else {swap(arr, cur, last--); // 大于划分标准,交换并前移记录最后一个当前元素的指针}}}private int randomizedSelect(int[] arr, int target) {int res = 0;for (int left = 0, right = arr.length - 1; left <= right;) {partition(arr, left, right, arr[left + (int) (Math.random() * (right - left + 1))]);if (target < first) {right = first - 1; // 当前下标小于维护的第一个下标,到左边区间中找} else if (target > last) {left = last + 1; // 当前下标大于维护的最后一个下标,到右边区间中找} else {res = arr[target]; // 当前下标在维护的范围内,记录结果break;}}return res;}
}

http://www.ppmy.cn/server/159186.html

相关文章

如何发布自己的第一个Chrome扩展程序

如何发布自己的Chrome扩展程序 只需要六步即可完成Chrome扩展程序的发布 &#xff08;1&#xff09;首先打开google chrome 应用商城注册开发者账号的页面 &#xff08;2&#xff09;现在进行一个绑卡支付5美元的一次性注册费用即可。【不知道如何绑卡的支付的&#xff0c;文…

YOLOv8改进,YOLOv8检测头融合RFAConv卷积,并添加小目标检测层(四头检测),适合目标检测、分割等

摘要 空间注意力已广泛应用于提升卷积神经网络(CNN)的性能,但它存在一定的局限性。作者提出了一个新的视角,认为空间注意力机制本质上解决了卷积核参数共享的问题。然而,空间注意力生成的注意力图信息对于大尺寸卷积核来说是不足够的。因此,提出了一种新型的注意力机制—…

Docker+Jenkins+Tomcat(保姆级教学)

为了防止文档发了没人看&#xff0c;我在文档里偷偷埋了几个雷 ? 1、简介 什么是持续集成&#xff08; Continuous integration &#xff09;&#xff1f; 持续集成是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员至少集成一 次…

Rust 零大小类型(ZST)

在 Rust 中&#xff0c;零大小类型&#xff08;Zero-Sized Type&#xff0c;简称 ZST&#xff09; 是指在内存中不占用任何存储空间的类型。这些类型的大小为 0 字节&#xff0c;编译器会对它们进行优化&#xff0c;避免为它们分配实际的存储空间。ZST 是 Rust 类型系统中一个非…

专题 - STM32

基础 基础知识 STM所有产品线&#xff08;列举型号&#xff09;&#xff1a; STM产品的3内核架构&#xff08;列举ARM芯片架构&#xff09;&#xff1a; STM32的3开发方式&#xff1a; STM32的5开发工具和套件&#xff1a; 若要在电脑上直接硬件级调试STM32设备&#xff0c;则…

ospf收敛特性及其他的小特性

1. 收敛特性 快速收敛&#xff1a;   只第一次计算时计算全部节点Full SPF   增量最短路径优先算法I-SPF&#xff08;Incremental&#xff09;    只对受影响的节点进行路由计算   全部路由计算PRC    只对发生变化的路由进行重新计算;    根据I-SPF 算出来的SPT …

如何解决Webview和H5缓存问题,确保每次加载最新版本的资源

WebView 用于加载 H5 页面是常见的做法&#xff0c;它能够加载远程的 HTML、CSS、JavaScript 资源&#xff0c;并且让 Web 应用嵌入到原生 App 中。然而&#xff0c;WebView 的缓存机制有时会导致用户看到的是旧版本的页面或资源&#xff0c;尤其是在 H5 发版后&#xff0c;iOS…

【数模学习笔记】插值算法和拟合算法

声明&#xff1a;以下笔记中的图片以及内容 均整理自“数学建模学习交流”清风老师的课程资料&#xff0c;仅用作学习交流使用 文章目录 插值算法定义三个类型插值举例插值多项式分段插值三角插值 一般插值多项式原理拉格朗日插值法龙格现象分段线性插值 牛顿插值法 Hermite埃尔…