首页 > 编程语言 >算法题:数组中的第K个最大元素

算法题:数组中的第K个最大元素

时间:2024-09-23 21:19:02浏览次数:11  
标签:堆顶 nums int 元素 算法 数组 排序

数组中的第K个最大元素

问题描述:在未排序的数组中找到第K个最大的元素。

解题思路:可以使用最小堆(优先队列)来解决这个问题。将数组中的元素依次加入最小堆中,当堆的大小超过K时,就弹出堆顶元素(即当前最小的元素)。最后,堆顶元素即为第K个最大的元素。

Java代码实现(这里使用Java的PriorityQueue实现最小堆):
在这段代码中,KthLargest 类实现了一个方法来找到数组中的第 k 大元素。这个方法利用了 Java 的 PriorityQueue 类,但这里有一个小技巧:尽管我们通常将 PriorityQueue 用作最大堆或最小堆,但在这里它被用作一个大小为 k 的最小堆来存储当前遇到的最大的 k 个数。这样,堆顶(peek 方法返回的元素)始终是这些数中最小的,但由于我们只关心最大的 k 个数,所以堆顶的元素实际上就是第 k 大的元素。以下是添加了注释的代码:

    /**
     * 找到数组中第k大的元素
     * @param nums 输入的整数数组
     * @param k 需要找到的第k大的元素的序号,注意这里的k是从1开始计数的
     * @return 数组中第k大的元素
     */
class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 小顶堆,堆顶是最小元素
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for (int e : nums) {
            // 每个元素都要过一遍二叉堆
            pq.offer(e);
            // 堆中元素多于 k 个时,删除堆顶元素
            if (pq.size() > k) {
                pq.poll();
            }
        }
        // pq 中剩下的是 nums 中 k 个最大元素,
        // 堆顶是最小的那个,即第 k 个最大元素
        return pq.peek();
    }
}
// 详细解析参见:
// https://labuladong.online/algo/slug.html?slug=xx4gT2

需要注意的是,这里的 k 是从 1 开始计数的,而不是从 0 开始。另外,虽然 PriorityQueue 的初始容量被设置为 k,但这并不意味着堆的大小会一直被限制在 k。实际上,在填充堆的初始阶段,堆的大小会随着元素的加入而增长,直到达到 k 个元素。之后,只有当遇到比堆顶元素还要大的元素时,堆顶元素才会被移除,新元素才会被加入堆中,从而保持堆中始终有 k 个当前遍历过的最大元素。

当然,除了使用最小堆(PriorityQueue)之外,还有其他几种方法可以实现找到数组中的第k大元素。以下是一些常见的替代方法:

1. 排序

最直接的方法是首先对数组进行排序(升序或降序都可以,但降序更直观),然后直接返回第k个元素(注意数组索引从0开始,所以实际上是第k-1个位置上的元素)。但这种方法的时间复杂度通常是O(n log n),其中n是数组的长度,因为排序操作通常需要这个时间复杂度。

import java.util.Arrays;

public class KthLargest {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums); // 对数组进行排序
        return nums[nums.length - k]; // 返回第k大的元素
    }
}

2. 快速选择(QuickSelect)

快速选择算法是快速排序算法的一个变种,用于在未完全排序的数组中找到第k小(或第k大)的元素。它的平均时间复杂度为O(n),但最坏情况下仍然是O(n^2)。快速选择通过选择一个“枢轴”(pivot)元素,将数组分为两部分,一部分包含所有小于枢轴的元素,另一部分包含所有大于枢轴的元素,然后递归地在包含第k个元素的那一部分继续搜索。

public class KthLargest {
    public int findKthLargest(int[] nums, int k) {
        return quickSelect(nums, 0, nums.length - 1, nums.length - k);
    }

    private int quickSelect(int[] nums, int left, int right, int k) {
        if (left == right) return nums[left];

        int pivotIndex = partition(nums, left, right);

        if (k == pivotIndex) {
            return nums[k];
        } else if (k < pivotIndex) {
            return quickSelect(nums, left, pivotIndex - 1, k);
        } else {
            return quickSelect(nums, pivotIndex + 1, right, k);
        }
    }

    // 这里省略了partition方法的实现,它负责将数组按照某个枢轴元素进行分区
}

3. 部分排序

在某些情况下,你可以使用部分排序算法(如堆排序的部分版本或基于比较的排序算法的部分执行)来找到第k大的元素,而不需要对整个数组进行排序。这种方法的时间复杂度可能介于O(n log k)O(n log n)之间,具体取决于实现方式。

4. 使用最大堆

虽然题目中使用了最小堆,但你也可以使用最大堆来存储当前遇到的最大的k个数。这样,堆顶元素将始终是最大的元素,而你需要找到的是第k大的元素,所以你需要从堆中移除堆顶元素(即最大元素)k-1次,然后堆顶元素就是第k大的元素。但这种方法相比最小堆来说效率较低,因为它需要额外的k-1次移除操作。

5. 线性选择算法(针对特定情况)

对于某些特定情况(如数组中的元素范围很小或具有其他特殊性质),可能存在线性时间复杂度的选择算法。但这些算法通常依赖于数组的特定性质,并不适用于一般情况。

综上所述,选择哪种方法取决于具体的应用场景和对时间复杂度的要求。在大多数情况下,快速选择算法是一个很好的选择,因为它在平均情况下具有线性时间复杂度。

标签:堆顶,nums,int,元素,算法,数组,排序
From: https://blog.csdn.net/qq_36329049/article/details/142469091

相关文章

  • 算法与数据结构学习路线图
    基础阶段编程语言基础:选择一门编程语言作为学习算法与数据结构的工具,如Python、Java、C++等,掌握其基本语法、数据类型、控制结构、函数等。这是后续学习的基础。学习时间:建议花费1-2个月左右打牢基础。学习网站及资源:菜鸟教程:网址为https://www.runoob.com/,提供各种编程......
  • leetcode刷题day27|贪心算法Part01(455.分发饼干、376. 摆动序列、53. 最大子序和)
    前言:贪心的本质选择每一阶段的局部最优,从而达到全局最优。455.分发饼干思路:局部最优-大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个;全局最优:喂饱尽可能多的小孩。可以尝试使用贪心策略,先将饼干数组和小孩数组排序,然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计......
  • 基于真实山地场景下的超多目标优化算法求解无人机三维路径规划,MATLAB代码
    超多目标优化算法是一类专门用于解决存在三个以上目标函数的最优化问题的算法。这类问题在现实世界中非常常见,例如在工程设计、资源管理、机器学习等领域。由于目标之间的冲突性,很难找到一个单一的解来同时优化所有目标,因此超多目标优化算法旨在找到一组解,这些解在目标之间......
  • leecode203-移除链表元素
    文章目录题目解题方法1题目给你一个链表的头节点head和一个整数val,请你删除链表中所有满足Node.val==val的节点,并返回新的头节点。示例1:输入:head=[1,2,6,3,4,5,6],val=6输出:[1,2,3,4,5]示例2:输入:head=[],val=1输出:[]示例3:输入:head......
  • ADAU1701的Dynamics Processors算法补充例程合集(10个例程)
    作者的话做ADAU1701,心血来潮,再过了一遍SigmaDSP的算法合辑,发现有不少遗留的,比较有特点的算法,就在这个系列文章里一一呈现吧。ADAU1701我写了超过100个例程,但是都很早期,2018年开始弄的,我感觉并不是很全,那这一次就彻底把他补全一下,这个系列文章,将把我能够找到的,ADI原厂提供......
  • XGBoost6种优化算法分类模型一键对比 +交叉验证 Matlab代码
    ......
  • 信息学奥赛复赛复习01-CSP-J2019-01-字符、字符数组、字符串、string、字符串读取
    信息学奥赛复赛复习01-CSP-J2019-01-字符、字符数组、字符串、string、字符串读取PDF文档公众号回复关键字:2024092312019CSP-J题目1数字游戏[题目描述]小K同学向小P同学发送了一个长度为8的01字符串来玩数字游戏,小P同学想要知道字符串中究竟有多少个1。注......
  • (一)Bluebell用户表结构设计及用户ID生成(雪花算法)
    一、用户表结构在mysql数据库中创建user表DROPTABLEIFEXISTS`user`;CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`user_id`bigint(20)NOTNULL,`username`varchar(64)COLLATEutf8mb4_general_ciNOTNULL,`password`varchar(64)COLLATEutf8......
  • 车辆目标检测、车辆识别、车辆类型检测算法
    车辆检测算法是计算机视觉和深度学习领域的一个重要应用,主要用于智能交通系统、停车场管理、交通流量监控、安全监控等多个领域。通过图像识别技术,车辆检测算法能够实时检测和识别图像或视频中的车辆,提供准确的车辆位置和类型信息。一、应用场景1.智能交通系统-交通流量管理:通......
  • [CSS] flexbox 布局中,让其元素均匀排列且如何均匀元素之间的 column-gao 和 row-gap
    要达到上图效果,可以通过margin,但是每一行首元素和尾元素都要单独处理,通过nth-child选择器设置。也可以让每一个元素宽度都是父元素宽度的25%,然后子元素宽度再一点点调试向下减一点点,比如22%合适,并且需要设置justify-content:space-between或者其他,但如果最后一行元素不......