首页 > 其他分享 >215. 数组中的第K个最大元素

215. 数组中的第K个最大元素

时间:2024-12-20 19:10:49浏览次数:4  
标签:215 nums int povit 元素 low 数组

数组中的第K个最大元素
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 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

思路

方案一:快速选择

题目要求找到给定数组 nums 中的第 k 大元素。为了实现这个目标,可以采用 快速选择 算法,这是一种基于快速排序的思想,可以在平均时间复杂度为 O(n) 的情况下解决这个问题。

快速选择(Quick Select)算法的核心思想

  1. 选择基准:选择数组中的一个基准元素,通常选择第一个元素或随机选择。
  2. 分区操作:通过划分操作,将数组分成两部分,基准元素左边的部分所有元素小于等于基准元素,右边的部分所有元素大于等于基准元素。
  3. 递归查找
    • 如果基准元素的索引正好是 k-1,则返回该元素。
    • 如果基准元素的索引大于 k-1,则继续在左半部分查找。
    • 如果基准元素的索引小于 k-1,则继续在右半部分查找。
class Solution {
    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        int low = 0, high = n - 1;
        while(true){
            int povit = partition(nums, low, high);
            if (povit == k-1){
                return nums[povit];
            }else if(povit > k-1){
                high = povit - 1;
            }else{
                low = povit + 1;
            }
        }
    }

    private int partition(int[] nums, int low, int high){
        int povit = nums[low];
        while(low < high){
            while(low < high && nums[high] <= povit) --high;
            nums[low] = nums[high];
            while(low < high && nums[low] >= povit) ++low;
            nums[high] = nums[low];
        }
        nums[low] = povit;
        return low;
    }
}

代码分析

findKthLargest 方法
  • 初始化
    • n:数组 nums 的长度。
    • low:指向数组的起始位置,初始为 0
    • high:指向数组的末尾,初始为 n - 1
  • 循环:使用 while(true) 来持续进行 快速选择 直到找到第 k 大的元素。
    • 调用 partition(nums, low, high) 方法来划分数组。
    • 基准值的索引 povit 是划分后的元素的索引,它是数组的一个"分界点"。
    • 判断 povit 是否等于 k - 1:
      • 如果 povit == k - 1,表示找到第 k 大的元素,直接返回 nums[povit]
      • 如果 povit > k - 1,说明第 k 大的元素在左半部分,因此将 high 更新为 povit - 1
      • 如果 povit < k - 1,说明第 k 大的元素在右半部分,因此将 low 更新为 povit + 1
partition 方法
  • 初始化
    • povit 是选定的基准元素,这里选定了 nums[low] 作为基准。
  • 划分过程
    • 使用两个指针 lowhigh,通过遍历来将数组中的元素分成两部分:小于等于基准的元素放在基准的左边,大于等于基准的元素放在右边。
    • 步骤:
      • 内层循环:从右边开始,寻找小于等于基准的元素,然后交换到左边。
      • 内层循环:从左边开始,寻找大于等于基准的元素,然后交换到右边。
    • 最终,基准元素 povit 会被交换到 low 索引的位置,数组被分成了两部分。
  • 返回值
    • 返回 low,即基准元素的最终位置。

方案二:堆

是一种常用的用于查找第 K 大/小元素的数据结构。可以使用最小堆(Min-Heap)或者最大堆(Max-Heap),具体选择哪一种取决于你是要查找第 K 大还是第 K 小元素。

小根堆(Min-Heap)求第 K 大元素

  • 小根堆的堆顶是最小的元素,所以它总是保持堆中最小的元素在堆顶。

  • 为了找到第 K 大元素,我们可以构建一个大小为 K 的小根堆,然后遍历数组中的其他元素:

    • 如果堆中有 K 个元素,且当前元素大于堆顶元素,就将堆顶元素移除,插入当前元素。
    • 最后,堆顶元素就是第 K 大的元素。

大根堆(Max-Heap)求第 K 小元素

  • 大根堆的堆顶是最大的元素,所以它总是保持堆中最大元素在堆顶。

  • 为了找到第 K 小元素,我们可以构建一个大小为 K 的大根堆,然后遍历数组中的其他元素:

    • 如果堆中有 K 个元素,且当前元素小于堆顶元素,就将堆顶元素移除,插入当前元素。
    • 最后,堆顶元素就是第 K 小的元素。

具体解释

  • 小根堆求第 K 大元素:我们使用小根堆维护一个包含 K 个最大元素的堆。由于小根堆的特性,堆顶是当前堆中最小的元素。因此,当堆中元素超过 K 个时,我们移除堆顶,保留较大的元素。最终堆顶就会是第 K 大的元素。
  • 大根堆求第 K 小元素:我们使用大根堆维护一个包含 K 个最小元素的堆。由于大根堆的特性,堆顶是当前堆中最大的元素。当堆中元素超过 K 个时,我们移除堆顶,保留较小的元素。最终堆顶就是第 K 小的元素。
class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();

        for(int num : nums){
            minHeap.add(num);
            //假如有m个元素,留下来的k个就等于是最大的那k个,
            //然后取这里面最小的一个就行了
            if(minHeap.size() > k){
                minHeap.poll();
            }
        }

        return minHeap.peek();
    }
}

标签:215,nums,int,povit,元素,low,数组
From: https://www.cnblogs.com/drunkerl/p/18619839

相关文章

  • 小发现-->对“删除”数组元素的不同做法
     删除的本质:对于数组元素删除,其实不能算是删除,毕竟你数组是一片连续存储的空间,你要是真的删除了一个地方那还了得了,所以删除无非就是在输出结果的时候看上去像是某个地方的元素被删除了,实际上呢,要么是被别的元素覆盖了,要么是被标记了,跳过了这个位置进行输出,那么接下来就对着......
  • C#调用c语言dll,并且传入byte数组或字符串,简单实例
    前言在C#中调用dll,可能会出现程序一开始可以运行,但过一会儿后出现内存错误——尝试读取或写入受保护的内存。这通常指示其他内存已损坏。这是由于C#的托管内存机制,而C语言中是非托管内存。如果参数传入dll后,C#提前回收了内存或者移动了数据,将会出现错误。解决方法是,在C#传入dll......
  • 53. 最大子数组和
    题目链接解题思路:子数组问题,考虑以i结尾,或者以i开头结果怎么样。本题,以i开头结果是如何?从后往前遍历,假设i+1的结果大于0,为x,那么,求i时,结果就是nums[i]+x,如果x小于0,那么结果就是nums[i]代码classSolution:defmaxSubArray(self,nums:List[int])->int:......
  • leetcode 2592. 最大化数组的伟大值
    2592.最大化数组的伟大值法一:排序丑陋的代码classSolution{public:intmaximizeGreatness(vector<int>&nums){sort(nums.begin(),nums.end());intsize=nums.size(),res=0;for(inti=0,j=0;i<size&&j<size;+......
  • 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-8- 元素高级定位技巧(详细教程)
    1.简介随着网页的复杂性和动态性的增加,自动化测试变得越来越重要。Playwright作为一款强大的无头浏览器测试库,提供了多种元素定位方式,使得我们能够轻松地对网页进行自动化操作。在基础的定位方式如通过id、classname和tagname等之外,Playwright还提供了更高级的定位技巧,如nth()......
  • 如何使用position:relative内的absolute元素水平和垂直居中?
    在前端开发中,我们经常需要使元素在其父元素内部水平和垂直居中。当父元素设置为position:relative,而子元素设置为position:absolute时,可以通过以下步骤实现:设置父元素为相对定位(position:relative):这会创建一个新的定位上下文,使得子元素的绝对定位是相对于这个父元素......
  • 写一个方法将多个数组合并成一个数组
    在前端开发中,JavaScript是一种常用的编程语言。在JavaScript中,你可以使用多种方法来合并数组。以下是一个简单的示例,展示如何使用Array.prototype.concat()方法来合并多个数组:functionmergeArrays(...arrays){letmergedArray=[];for(leti=0;i<arrays.......
  • 对非可点击元素如(span)的click事件在有些手机上不触发如何解决?
    对于非可点击元素(如<span>)的click事件在某些手机上不触发的问题,这通常是由于这些元素默认不是为交互设计的。移动浏览器或特定的浏览器引擎可能会对这些元素的点击事件进行优化或忽略,尤其是在涉及到性能或用户体验的情境中。为了解决这个问题,你可以尝试以下几种方法:添加cu......
  • Java学习,数组中查找指定元素
    Java中查找数组中的指定元素是一个常见的操作。数组中查找指定的元素,并返索引:publicclassFindElementInArray{  publicstaticvoidmain(String[]args){    int[]numbers={10,20,30,40,50};    inttarget=30;    intindex......
  • Java学习,数组是否相等
    Java中判断两个数组是否相等,不是直接的事情,数组对象之间的 equals()方法,并不会逐个比较数组元素,是比较数组对象的引用是否相同(即它们是否指向内存中同一个位置)。要判断两个数组,是否包含相同的元素并且顺序也相同。判断两个整数数组是否相等publicclassArrayEqualityChecke......