堆----1.数组中的第K个最大元素

215. 数组中的第K个最大元素 - 力扣(LeetCode)

/**

第一大元素--->len - 1

第二大元素--->len - 2

.......

第K大元素---->len - K,则数组中第K个最大元素,转化为寻找排序后第len - K位置的元素

快速选择算法:

快速排序的变种,核心的分区函数一致,在数组中随机选择一个基准 pivot

按基准将数组划分为三个部分 小于基准 基准 大于基准,那么此时基准所在的位置就是排序后该在的位置

变种:

在本题中,若划分后基准所在位置恰好是len - k,那么说明基准就是第K个最大元素

若基准 < len - K, 则减小范围,在基准 + 1,right中重新选择基准,重复上述流程

若基准 > len - K, 则减小范围,在left, 基准 - 1中重新选择基准,重复上述流程

直到找到为止

分区函数(核心):

首先在数组中随机选择一个元素为基准元素,从左右两端同时开始扫描

左指针向右遍历,直到遇到第一个>=pivot的元素

右指针向左遍历,直到遇到第一个<=pivot的元素

交换左右指针的值,交换后,大于基准元素的在右半区,小于基准元素的在左半区,等于基准元素的平均分布在左、右半区

细节注意:

在选择出基准元素后,将其移至数组首位

遍历完毕后基准元素与左指针交换位置,将基准元素移动至正确位置

*/

java 复制代码
class Solution {
    /**
        第一大元素--->len - 1
        第二大元素--->len - 2
        .......
        第K大元素---->len - K,则数组中第K个最大元素,转化为寻找排序后第len - K位置的元素
        快速选择算法:
                    快速排序的变种,核心的分区函数一致,在数组中随机选择一个基准 pivot
                    按基准将数组划分为三个部分 小于基准 基准 大于基准,那么此时基准所在的位置就是排序后该在的位置
                变种:
                    在本题中,若划分后基准所在位置恰好是len - k,那么说明基准就是第K个最大元素
                    若基准 < len - K, 则减小范围,在[基准 + 1,right]中重新选择基准,重复上述流程
                    若基准 > len - K, 则减小范围,在[left, 基准 - 1]中重新选择基准,重复上述流程
                    直到找到为止
                分区函数(核心):
                    首先在数组中随机选择一个元素为基准元素,从左右两端同时开始扫描
                    左指针向右遍历,直到遇到第一个>=pivot的元素
                    右指针向左遍历,直到遇到第一个<=pivot的元素
                    交换左右指针的值,交换后,大于基准元素的在右半区,小于基准元素的在左半区,等于基准元素的平均分布在左、右半区
                细节注意:
                    在选择出基准元素后,将其移至数组首位
                    遍历完毕后基准元素与左指针交换位置,将基准元素移动至正确位置
    */

    private int[] nums;
    private int target;
    private final Random random = new Random();

    public int findKthLargest(int[] nums, int k) {
        this.nums = nums;
        this.target = nums.length - k;

        quickSelect(0,nums.length - 1);
        return nums[target];
    }

    //快速选择
    private void quickSelect(int left, int right) {
        if(left > right) {
            return;
        }

        int pivotIndex = partition(left, right); //得到第一个有序的位置

        if(pivotIndex == target) { 
            return;
        } else if(pivotIndex < target) {
            quickSelect(pivotIndex + 1, right); //[基准 + 1,right]
        } else {
            quickSelect(left,pivotIndex - 1); //[left, 基准 - 1]
        }
    }

    //分区函数
    private int partition(int left, int right) {
        //生成随机基准
        int pivot = random.nextInt(right - left + 1) + left;
        int pivotValue = nums[pivot];
        swap(left,pivot); //先将基准移至首位

        //双端同时开始扫描
        int le = left + 1;
        int ge = right;
        
        while(true) {
            //左指针向右遍历,直到遇到第一个>=pivot的元素
            while(le <= ge && nums[le] <pivotValue) {
                le++;
            }

             //右指针向左遍历,直到遇到第一个<=pivot的元素
            while(le <= ge && nums[ge] > pivotValue) {
                ge--;
            }

            //遍历结束退出
            if(le >= ge) {
                break;
            }

            //交换两指针的值,进行分区
            swap(le,ge);
            le++;
            ge--;

        }

        //遍历完毕后基准元素与左指针交换位置,将基准元素移动至正确位置
        swap(left,ge);
        return ge;
    }

    private void swap(int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}
相关推荐
huangdong_3 小时前
电商平台图片URL原图转换技术深度解析:从缩略图到高清原图的完整方案
java·后端·spring
記億揺晃着的那天4 小时前
Java 调用外部 Go 程序的实践:ProcessBuilder 在生产环境中的应用
java·golang·processbuilder
JAVA面经实录9174 小时前
Java 数据结构与算法 (终极完整学习文档)
java·数据结构·算法
JAVA面经实录9174 小时前
操作系统面试题
java·服务器·数据库·计算机网络·面试
一杯奶茶¥5 小时前
基于springboot的失物招领管理系统带万字文档 校园失物招领管理系统 失物认领管理系统java springboot vue
java·vue.js·spring boot·java项目
不能只会打代码5 小时前
边缘视频分析平台的架构设计与性能优化——从750ms到190ms的调优之路
java·spring boot·redis·性能优化·边缘计算·物联网竞赛
小刘|5 小时前
Spring AI Alibaba 集成和风天气 API 实战
java·服务器·前端
KANGBboy5 小时前
java知识五(继承)
java·开发语言
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题 第117题】【并发篇】第17题:线程有几种状态,之间如何转换?
java·开发语言·面试
DIY源码阁5 小时前
JavaSwing饮品管理系统 - MySQL版
java·数据库·mysql·eclipse