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

news2025/1/15 8:32:17

问题背景

给定整数数组 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 + 1
        int 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.coloradmin.cn/o/2276911.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Angular-生命周期及钩子函数

什么是生命周期 Angular 创建和渲染组件及其子组件&#xff0c;当它们绑定的属性发生变化时检查它们&#xff0c;并在从 DOM 中移除它之前销毁它们。生命周期函数通俗的讲就是组件创建、组件更新、组件销毁的时候会触发的一系列的方法。当 Angular 使用构造函数新建一个组件或…

vue(五)基础语法--循环遍历指令

目录 简单数据的处理&#xff08;常用&#xff09; 复杂数据&#xff08;json数据&#xff09; v-for 与对象 通过key管理状态 Key的来源 这一节类同于vue&#xff08;四&#xff09;基础语法--条件渲染-CSDN博客 &#xff0c;本质都是那些基础语句语法的实现。 简单介绍 …

【全套】基于分类算法的学业警示预测信息管理系统

【全套】基于分类算法的学业警示预测信息管理系统 【摘 要】 随着网络技术的发展基于分类算法的学业警示预测信息管理系统是一种新的管理方式&#xff0c;同时也是现代学业预测信息管理的基础&#xff0c;利用互联网的时代与实际情况相结合来改变过去传统的学业预测信息管理中…

解决线程安全问题,Lock锁,死锁以及如何避免,线程的通信和线程池

如何解决线程安全问题 当多个线程共享一个资源时&#xff0c;则可能出现线程安全问题。 java中解决线程安全的方式有三种 第一种: 同步代码块 第二种: 同步方法 第三种: Lock 同步代码块 synchronized(锁对象){ 需要同步的代码。 } synchronized 同步的意思 锁对象可以是任…

源码编译安装httpd 2.4,提供系统服务管理脚本并测试(两种方法实现)

方法一&#xff1a;使用 systemd 服务文件 sudo yum install gcc make autoconf apr-devel apr-util-devel pcre-devel 1.下载源码 wget https://archive.apache.org/dist/httpd/httpd-2.4.46.tar.gz 2.解压源码 tar -xzf httpd-2.4.46.tar.gz 如果没有安装tar 记得先安装…

基于微信小程序的智能停车场管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

LabVIEW驱动电机实现样品自动搜索

利用LabVIEW控制电机驱动相机在XY平面上进行扫描&#xff0c;以检测样品位置。样品最初可能位于相机视野范围之外&#xff0c;需要实现自动搜索样品位置并完成精确定位扫描的功能。该系统需具有以下特点&#xff1a; 高效搜索&#xff1a;能够快速确定样品位置&#xff0c;缩短…

excel 整理表格,分割一列变成多列数据

数据准备 对于很多系统页面的数据是没有办法下载的。 这里用表格数据来举例。随便做数据的准备。想要看excel部分的可以把这里跳过&#xff0c;从数据准备完成开始看。 需要一点前端基础知识&#xff0c;但不多&#xff08;不会也行&#xff09;。 把鼠标放在你想要拿到本地的…

MAC AndroidStudio模拟器无网络

先确认PC端是正常访问网络的&#xff1b; 模拟器端修改Wifi设置&#xff1a;设置 - 网络和互联网 - WALN设置 按照上图修改&#xff1b; IP设置&#xff1a;从DHCP修改为静态&#xff0c;IP地址&#xff1a;10.0.2.16 &#xff0c;网关&#xff1a;10.0.2.2 &#xff0c; DNS…

【Linux系统】Ext系列磁盘文件系统一

0. 从快递系统引入文件系统 理解文件系统&#xff1a;菜鸟驿站的类比 在日常生活中&#xff0c;我们常常会使用到快递服务来寄送和接收包裹。这个过程虽然看似简单&#xff0c;但背后却有着一套复杂而有序的管理系统在支撑。今天&#xff0c;我们将通过一个类比——将文件系统…

1Hive概览

1Hive概览 1hive简介2hive架构3hive与Hadoop的关系4hive与传统数据库对比5hive的数据存储 1hive简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 其本质是将SQL转换为MapReduce/Spark的任务进…

Elasticsearch入门学习

Elasticsearch是什么 Elasticsearch 是一个基于 Apache Lucene 构建的分布式搜索和分析引擎、可扩展的数据存储和矢量数据库。 它针对生产规模工作负载的速度和相关性进行了优化。 使用 Elasticsearch 近乎实时地搜索、索引、存储和分析各种形状和大小的数据。 特点 分布式&a…

[读书日志]8051软核处理器设计实战(基于FPGA)第七篇:8051软核处理器的测试(verilog+C)

6. 8051软核处理器的验证和使用 为了充分测试8051的性能&#xff0c;我们需要测试每一条指令。在HELLO文件夹中存放了整个测试的C语言工程文件。主函数存放在指令被分为五大类&#xff0c;和上面一样。 打开后是这样的文件结构。HELLO.c是主文件&#xff0c;这是里面的代码&am…

【Vue实战】Vuex 和 Axios 拦截器设置全局 Loading

目录 1. 效果图 2. 思路分析 2.1 实现思路 2.2 可能存在的问题 2.2.1 并发请求管理 2.2.2 请求快速响应和缓存带来的问题 3. 代码实现 4. 总结 1. 效果图 如下图所示&#xff0c;当路由变化或发起请求时&#xff0c;出现 Loading 等待效果&#xff0c;此时页面不可见。…

一文读懂yolo11模型训练

一文读懂yolo11模型训练 一、环境准备 Anaconda安装 简介 Anaconda 是一个流行的开源 Python 发行版&#xff0c;专注于数据科学、机器学习、科学计算和分析等领域。它提供了一个强大的包管理器和环境管理器&#xff0c;名为 Conda&#xff0c;以及一个预装了大量科学计算和…

Apache PAIMON 学习

参考&#xff1a;Apache PAIMON&#xff1a;实时数据湖技术框架及其实践 数据湖不仅仅是一个存储不同类数据的技术手段&#xff0c;更是提高数据分析效率、支持数据驱动决策、加速AI发展的基础设施。 新一代实时数据湖技术&#xff0c;Apache PAIMON兼容Apache Flink、Spark等…

音视频入门基础:RTP专题(1)——RTP官方文档下载

一、引言 实时传输协议&#xff08;Real-time Transport Protocol&#xff0c;简写RTP&#xff09;是一个网络传输协议&#xff0c;由IETF的多媒体传输工作小组1996年在《RFC 1889》中公布的。 RTP作为因特网标准在《RFC 3550》有详细说明。而《RFC 3551》详细描述了使用最小…

【Vim Masterclass 笔记13】第 7 章:Vim 核心操作之——文本对象与宏操作 + S07L28:Vim 文本对象

文章目录 Section 7&#xff1a;Text Objects and MacrosS07L28 Text Objects1 文本对象的含义2 操作文本对象的基本语法3 操作光标所在的整个单词4 删除光标所在的整个句子5 操作光标所在的整个段落6 删除光标所在的中括号内的文本7 删除光标所在的小括号内的文本8 操作尖括号…

LiveGBS流媒体平台GB/T28181常见问题-没有收到视频流播放时候提示none rtp data receive未收到摄像头推流如何处理?

LiveGBS没有收到视频流播放时候提示none rtp data receive未收到摄像头推流如何处理&#xff1f; 1、none rtp data receive2、搭建GB28181视频直播平台 1、none rtp data receive LiveSMS 收不到下级推流 首先需要排查服务器端 UDP & TCP 30000-30249 端口是否开放其次排…

使用Docker模拟PX4固件的无人机用于辅助地面站开发

前言 最近在制作鸿蒙无人机地面站&#xff0c;模仿的是QGroundControl&#xff0c;协议使用mavlink&#xff0c;记录一下本地模拟mavlink协议通过tcp/udp发送 废话不多说直接上命令 1.启动docker的桌面端 启动之后才能使用docker命令来创建容器 docker run --rm -it jonas…