java数据结构与算法刷题-----LeetCode215. 数组中的第K个最大元素

Java实现 LeetCode 215. 数组中的第K个最大元素 215. 数组中的第K个最大元素 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 cla... 阅读详情
java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.youkuaiyun.com/grd_java/article/details/123063846

在这里插入图片描述

1. 堆排序

解题思路:时间复杂度O( n ∗ l o g 2 n n*log_2n n∗log2​n),使用小根堆会达到近乎O(n),空间复杂度O( l o g 2 n log_2{n} log2​n)
  1. 使用小根堆,建堆时间复杂度O(k),调整堆(删除堆顶并插入新元素)O( n ∗ l o g 2 k n*log_2k n∗log2​k),其中k是题目要求的返回第k最大元素。因此小根堆大小为k,故建堆为O(k). 共计O( k + n ∗ l o g 2 k k+n*log_2k k+n∗log2​k) = O(n)
  2. 不断地将元素插入到小根堆(根最小,其它元素都比根大)中,当堆中有k个元素,此时还需要往堆中插入元素时,需要进行判断。
  3. 因为此时堆顶元素正好是堆中倒数第k大元素。如果新插入元素比堆顶大。证明当前堆顶不是倒数第k大
  4. 则堆顶删除,并将新元素插入。此时调整堆,新的堆顶元素为第k大。以此类推。直到所有元素入堆后。
  5. 最终返回堆顶即可。
堆排序https://blog.youkuaiyun.com/grd_java/article/details/136937525
代码:当前官方增加了很多测试用例,已经无法超越100%的用户了,目前最快的算法,只能达到17ms,进行优化后,也只到了15ms。我查看2021年提交时的记录,是3ms超越100%。目前已经无法达到了。
  1. 使用Java提供的优先级队列实现小根堆(面试时候肯定不让你用。因此这个代码帮你理解整体的思路。然后第二个实现方法,我们需要自己实现小根堆)
    在这里插入图片描述
class Solution {
    //[6,5]
    //
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
            //返回值>0,o1放在o2后面。反之o1放o2前面
            //小根堆,小的在前面。利用o1-o2实现。如果o1小,o1-o2<0,o1会放在o2前面
            //如果o1大o2小,o1-o2>0,o1会放在o2后面。而小的o2放在o1前面
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        for(int num:nums){
            if(queue.size() == k){
                if(queue.peek() < num) {
                    queue.poll();
                    queue.offer(num);
                }
            }else{
                queue.offer(num);
            }
        }
        return queue.poll();
    }
}
  1. 自己实现小根堆,因为Java自带容器加了很多健壮性和线程安全的逻辑,所以效率较慢,我们自己实现小根堆就会快很多。
    在这里插入图片描述
class Solution {
        public int findKthLargest(int[] nums, int k) {
        int[] minHeap = new int[k];//小根堆
        for (int i = 0; i < k; i++) {//大小为k
            minHeap[i] = nums[i];
        }
        //k/2-1是二叉树的知识,代表以k个结点构成的二叉树的第一个非叶子结点。k/2-2是第二个非叶子,以此类推。i == 0是整个二叉树的根结点
        for (int i = k / 2 - 1; i >= 0; i--) {//调整小根堆,从下到上,依次让每一颗子树满足小根堆
            adjustHeap(minHeap, i);//i是二叉树的每个非叶子结点,小根堆的要求是:每个子树,根结点都是整棵树最小
        }
        //小根堆构建完成后,minHeap[0]就是当前第k大的数。接下来需要不断进行判断和入堆操作
        for (int i = k; i < nums.length; i++) {
            if (nums[i] > minHeap[0]) {//如果当前i,是比小根堆堆顶更大的元素,那么堆顶不是第k大,
                minHeap[0] = nums[i];//将堆顶出堆,并将i放在堆顶位置
                adjustHeap(minHeap, 0);//此时很有可能小根堆逻辑被破坏,也就是i太大,不满足小根堆,因此需要让i进行下降调整,让其重新满足小根堆定义
            }
        }
        return minHeap[0];
    }

    /**
     * 以root为根结点构建/调整堆
     * @param array 堆
     * @param root 当前根结点
     */
    private void adjustHeap(int[] array, int root) {
        //让root结点下降到合适位置,以满足小根堆效果(任何一颗子树,根结点都是最小的)
        while (true) {//当堆调整完成后,结束
            int left = 2 * root + 1;//获得root的左子结点下标
            int right = left + 1;//获得root的右子结点下标
            int min = root;//最小值,最终需要放到root结点位置
            //如果左子结点存在,并且左子结点更小,让min指向这个结点
            if (left < array.length && array[left] < array[min]) min = left;
            //如果右子结点存在,并且右子结点更小,让min指向这个结点
            if (right < array.length && array[right] < array[min]) min = right;
            //如果min == root说明小根堆调整结束
            if (min == root) break;
            //让min当前指向位置和root交换,也就是下降操作,说明root当前指向的结点不是最小值,不满足小根堆
            //因为小根堆,越上面层次的结点,越小,所以如果当前root太大,需要让其下降
            swap(array, root, min);
            //root本次下降完成后,min的位置是root新的位置。因为root下降到min的位置
            //让root指向min,然后继续循环,判断是否root需要继续下降。直到它下降到合适位置
            root = min;
        }
    }

    private void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

2. 快速选择

堆排序方便将K个数全找出来,例如数组中最大的k个数。如果只是找第k大数,有点大材小用。因为堆排序需要操作很多与第k大数无关的k-1,k-2…这些数。
而快速选择是快速排序的创始人针对解决单独只想找到某一个数字的问题而创作的算法,它不需要类似快速排序每一趟确定一个数字的最终位置。这个算法只关心第K个元素的位置。因此它的时间复杂度来到了O(n)

解题思路
  1. 我们每次都找到区间中间位置的数x
  2. 以x为基枢,保证当前区域,所有小于x的放在x左边,大于x的放在x的右边
  3. 如果x左边够k个数,就继续去左边处理,如果左边不够k个数,就去右边处理

如果左边部分没有第k大数,那就去右边找,此时左边部分的 leftNums个数,都已经确定都比第k大数小,所以k - leftNums为下轮右边部分该找的值。这一点很重要,会节省很多操作。这也是为什么我这个算法在官方测试用例增加后依然可以跑进3ms。而官方的写法只能在11ms。

代码:因为时间复杂度比堆更低,因此更快

在这里插入图片描述

class Solution {
    //程序入口
    public int findKthLargest(int[] _nums, int k) {
        int n = _nums.length;
        return quickselect(_nums, 0, n - 1, n-k+1);
    }
    //交换值
    void swap(int[] a,int i,int j){
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    //快速选择
    int quickselect(int[] a, int left, int right, int k) {
        if(left >= right) return a[left];
        int x = a[left + right >> 1];//获取当前区间中间的数x
        //借助两个下标,让比x小的去x左边,比x大的去右边
        int leftIndex = left - 1, rightIndex = right + 1;//分别代表区间中应该在x左边(<=x)的下标和x右边的下标
        while(leftIndex < rightIndex){
            do leftIndex++;while(a[leftIndex] < x);//当leftIndex指向的值,>=x时,终止循环
            do rightIndex--;while(a[rightIndex] > x);//当rightIndex指向的值,<=x时,终止循环
            if(leftIndex < rightIndex){//如果leftIndex目前在x左边,而且rightIndex目前在x右边,说明他俩的指向的值应该调换位置
                swap(a,leftIndex,rightIndex);//让小的去x左边leftIndex位置,大的去x右边rightIndex位置
            }
        }//直到目前区间实现x是中位数,左边都比x小,右边都比x大为止
        //此时rightIndex必然指向第一个比x小的值(也就是x比它小的左边部分的边界)
        if(k <= (rightIndex - left + 1)) //如果left到rightIndex区间(比x小的左边部分),正好够我们找到第k大数
            return quickselect(a,left,rightIndex,k);//进入左边区间继续寻找
        else //如果左边部分没有第k大数,那就去右边找,此时左边部分的 rightIndex - left + 1已经确定都比第k大数小,所以k - 左边部分为下轮右边部分该找的值
            return quickselect(a,rightIndex+1,right,k-(rightIndex-left+1));//右边部分找第(k - 左边部分个数)大的数。
    }
}
LeetCode 热题 HOT 100 (215. 数组中的第K个最大元素) Quickselect 利用分治思想,通过一次分区就能缩小问题规模,平均时间复杂度为 O(n)。这样可以降低最坏情况出现的概率,从而在大部分情况下实现 O(n) 的性能。因为 Quickselect 常用于求第 k 小的元素,所以要求第 k 个最大元素时,需要转换为第n - k个最小元素。分区操作与快速排序类似,通过不断交换元素使得 pivot 位置确定。 阅读详情

相关推荐

LeetCode215:数组中的第K个最大元素(数组-排序算法-分治算法-堆排序)

LeetCode215:数组中的第K个最大元素(数组-排序算法-分治算法-堆排序) 1、在未排序的数组中找到第 k 个最大的元素。你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 方法一:调用库函数: 直接调用库函数 public int findKthLargest(int[] nums, int k) { Arrays.sort(nums); return nums[nums.length-k]; } 方法二:快

cui1004的博客 774

【LeetCode】215. 数组中的第K个最大元素(Java)

快速排序算法基于快速排序的思想衍生,其可以使某些需要 O(NlogN) 时间复杂度的问题,在平均复杂度 O(N) 下完成。常见的例子是求数组中的第 k 小的数。在这种情况下,优先级队列的头是队列中最小的元素,请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。add() - 将指定的元素插入队列。输入: [3,2,3,1,2,4,5,5,6], k = 4。输入: [3,2,1,5,6,4], k = 2。

weixin_53235104的博客 1094

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

是一道非常经典的数组排序与查找问题,也是面试中非常常见的问题。考察重点包括:排序、堆排序、快速选择等多种方法,其中需要快速定位第K个最大元素。快速选择是快速排序的变种,只关注目标元素所在的部分,不需要对整个数组完全排序。个元素的小顶堆,其中堆顶元素始终为当前堆中最小的元素。根据场景选择合适解法,可以快速 AC 本题!遍历完成后,堆顶元素就是第。

互联网架构师笔记 1421

Linux与数据结构 2019-3-17下午

2.排序二叉树 2.1 创建一个排序二叉树 1.对于一个排序二叉树,我们知道其所有左子树上的元素的值都比根节点的值小,其所有右子树上的元素的值都比根节点大,因此很容易就可以构建一颗排序二叉树; 2.我们使用一个函数来对其中的节点进行添加,我们需要将左子树上的所有节点的值都小于根节点的值,将右子树上的值都大于根节点的值,因此我们需要有一个节点来存储添加的节点的值; typedef struct ...

weixin_42896619的博客 255

LeetCode——215,数组中的第K个最大元素(分治法)

/** * \* Created: liuhuichao * \* Date: 2020/1/27 * \* Time: 11:32 上午 * \* Description: 数组中的第K个最大元素 * \ * 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 * <p> * 示例 1: * ...

我们的征途是星辰大海 1456

展锐双摄帧同步实战:从配置到调试的完整避坑指南

本文深入剖析了在展锐平台上实现双摄帧同步的完整流程与核心技术。详细对比了硬件帧同步与软件帧同步的差异、应用场景及核心挑战,提供了从XML配置、驱动层适配到调试验证的实战指南。重点强调了硬件帧同步必须与固定帧率强绑定这一关键避坑点,并分享了针对景深虚化等场景的同步质量验证方法及长稳测试策略。

kiwi8的博客 403

leetcode 215. Kth Largest Element in an Array | 215. 数组中的第K个最大元素(Java)

题目 https://leetcode.com/problems/kth-largest-element-in-an-array/ 题解 本题需要建立大顶堆。关于堆的数据结构,需要知道: 堆 什么是堆? 堆 是一棵 完全二叉树:即使它不是满二叉树,也是正在从左往右变满的过程中。 1)堆结构就是用数组实现的完全二叉树结构 2)完全二叉树中,如果每棵子树的 最大值都在顶部,是 大根堆 3)完全二叉树中,如果每棵子树的 最小值都在顶部,是 小根堆 4)堆结构的 heapInsert 与 heapify 操作

寒泉 5万+

硬全桥副边钳位管Vds电压凸台揭秘——寄生参数引发的导通异常

本文深入分析了硬全桥副边钳位管Vds电压凸台现象,揭示了寄生参数如何引发导通异常。通过波形分析和工程实践,详细解析了走线电感的蓄能效应和体二极管的接力作用,并提供了PCB布局优化、元件选型和驱动电路调整等解决方案,帮助工程师有效应对这一常见问题。

weixin_30825581的博客 430

leetcode215. 数组中的第K个最大元素(java)

快速排序(Quick Sort)是一种常用的排序算法,其基本思想是将一个数组按照某个关键字进行划分,将小于关键字的元素放在左侧,大于关键字的元素放在右侧,然后递归地对左右两个子数组进行排序,最终得到有序的数组。这样数组大范围内上就是有序的,小范围内是无序的,根据大范围内有序,我们就可以淘汰掉一边,左边或者右边的数字,我们就可以淘汰掉,这个里是找第K 大的元素,我们可以把过程改写下,让大于的放左边,小于的放右边,整体递减的顺序,这样方便查找。输入: [3,2,3,1,2,4,5,5,6], k = 4。

SP_1024的博客 372

SAP中成本估算没有找到工艺路线消息处理实例

在针对成品的标准成本核算处理过程中,系统中会经由设定好的策略来收集成品相关成本组成,最终计算出产成品的标准成本。关于成本组成,可以归纳为三个基本要素,料,工,费。即标准成本就是要知道,生产一件成品,需要消耗多少钱的原材料?消耗多少钱的人工?以及其它的间接消耗? 某日,接到CO同事的反馈,在用CK11N做产成品标准价格核算时,提示没有工艺路线确定,但该消息为绿灯,可以通过。基于业务上的谨慎,提出分析。 从提示可以看出问题与工艺路线有关。因为,成品工艺路线中设定有成品生产所耗工时,所以,在计算产成品标准

专注SAP应用技术文章写作,致力于拉近用户与系统间的距离; 6281

多模态融合相关概念

多模态图像融合

weixin_43921949的博客 7367

LeetCode(215):数组中的第K个最大元素 Kth Largest Element in an Array + 快速排序(Java)

2019.7.30 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新) 这题主要有两种思路: 1.借助最小堆/最大堆。为了减小插入时候的比较次数,可以控制最小堆最多始终不超过k个结点,遍历完数组后最小堆堆顶元素即为第K个最大元素。 2.借助快排思想。快排的每一次partition操作会将数组的枢纽元素pivot放在其排序后的最终位置,不断二分迭代直到当前pivot的位置恰为n...

NJU_ChopinXBP的博客 371

RGMII时序约束

RGMII时序约束

wudpekerlily的博客 5064

【中等】力扣算法题解析LeetCode215:数组中的第K个最大元素

题目要求在整数数组中找到第 k 个最大的元素。通过快速选择算法(QuickSelect)实现,该算法基于快速排序的分区思想,但仅处理包含目标元素的子数组。关键步骤包括:将问题转换为升序第 nums.length - k 小的元素,随机选择枢轴进行分区,通过双指针调整数组,并根据枢轴位置迭代搜索目标区间。Java实现中,使用Lomuto分区方案和随机枢轴优化性能,确保平均时间复杂度为 O(n)。代码通过交换和迭代处理,高效定位目标元素。

ylumwd的博客 1310

SQLite学习——Dapper初识

dapper下载:https://www.nuget.org/packages/Dapper/1.40.0

jiDxiaohuo的博客 1305

(SEED-Lab)Buffer Overflow Vulnerability Lab缓冲区溢出实验

(SEED-Lab)Buffer Overflow Vulnerability Lab 欢迎大家访问我的GitHub博客 https://lunan0320.cn 文章目录一、实验目的二、实验步骤与结果2.1 环境初始化2.2 Task1 运行shellcode2.3漏洞程序2.4 Task 22.5 Task 3: ASLR2.6 Task 4: Stack Guard2.7 Task 5:不可执行栈三、参考文献 一、实验目的 理解缓冲区溢出攻击的原理以及如何实施攻击 理解针对缓冲区溢出的防御措施

lunan的博客 8983

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

划分,对于测试未通过的案例,即为一个极端案例。【该题leetcode的官方题解非常清晰,建议仔细阅读。为同一种算法代码实现,提交均为超出时间限制,未通过测试案例均为同一个,的大小关系将要排序的数据分成独立的两个部分,其中一部分的所有数据都比。元素,则已经找到答案,而不用关心左右两个区间中的数字是否有序。该题代码开发工作量略大,主要是边界问题的处理具体。中忽略了子区间仅为两个元素的情况,故造成错误;在左区间,则递归左区间,否则递归右区间。具体的,在实现过程中,若该位置。大),另外一部分的所有数据比。

用魔法打败魔法,走楼梯啊! 1080

AMD机密计算虚拟机介绍

AMD机密计算虚拟机介绍

木简熙的博客 535

【LeetCode 热题 100】215. 数组中的第K个最大元素——(解法二)最小堆

Problem:给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

最短的捷径就是绕远路,绕远路才是我的最短捷径。 1480

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

LeetCode 215. 数组中的第K个最大元素 快速选择详解 Java实现

快速选择算法在处理找到第k个最大元素的问题时表现出色,时间复杂度为O(n),适合处理较大规模的数组。

Lentr0py的博客 1363

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

LeetCode 215:数组中的第K个最大元素 - 两种高效解法详解

在算法面试中,查找数组中第K个最大元素是一个经典问题。LeetCode第215题要求我们在未排序的数组中找到第K大的元素。本文将介绍两种高效的解决方案:快速选择算法和堆(优先队列)方法,帮助你全面掌握这道高频面试题。

weixin_44435110的博客 1629

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

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

LeetCode 215 数组中的第K个最大元素 Java题目描述代码 题目描述 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是...

qq_29061435的博客 222

Java算法精讲:215.数组中的第K个最大元素

一道经典面试题:如何在 O(n) 时间复杂度内找到数组中第 K 大的元素?直接排序(O(n log n))不符合要求,需更优解法。

Liamk_super的博客 1032

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

目录 方法一:暴力解法 方法二:借助 partition 操作定位到最终排定以后索引为 len - k 的那个元素(特别注意:随机化切分元素) 方法三:优先队列(默认是最大堆) 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是.

大叶子不小的博客 2170

【LeetCode: 215. 数组中的第K个最大元素 + 快速选择排序】

【LeetCode: 215. 数组中的第K个最大元素 + 快速选择排序】给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

Coder_ljw的博客 765
上一篇: 板绘学习路线、技巧和日常练习-----入门绘画:Q版漫画---持续补充
下一篇: java数据结构与算法基础-----排序------堆排序
ydenergy_殷志鹏
博客等级 码龄7年 5887粉丝 543原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydenergy_殷志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值