LeetCode Hot100 215. 数组中的第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

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

代码&注释

java 复制代码
class Solution {
    /**
     * 查找数组中第 k 个最大的元素(即第 k 大)
     * 
     * 思路:先对整个数组进行升序排序,然后第 k 大就是倒数第 k 个元素,
     *       即索引为 nums.length - k 的元素。
     * 
     * 注意:此方法时间复杂度为 O(n log n),不是最优解(最优可用快速选择,平均 O(n)),
     *       但逻辑简单、易于理解。
     * 
     * @param nums 输入数组
     * @param k 第 k 大(k 从 1 开始计数)
     * @return 第 k 个最大的元素;若输入非法,返回 0
     */
    public int findKthLargest(int[] nums, int k) {
        // 边界检查:数组为空、长度为 0 或 k 超出范围
        if (nums == null || nums.length == 0 || k > nums.length) {
            return 0;
        }
        
        // 对整个数组进行升序快速排序
        quick_sort(nums, 0, nums.length - 1);
        
        // 排序后,第 k 大的元素位于倒数第 k 个位置
        // 例如:[1,2,3,4,5],第 2 大是 4,索引 = 5 - 2 = 3
        return nums[nums.length - k];
    }

    /**
     * 快速排序(递归实现,原地排序)
     * 
     * 采用"三路划分"思想的简化版(实际是标准双指针分区)
     * 目标:将数组 [l, r] 区间按升序排列
     * 
     * @param nums 待排序数组
     * @param l 左边界(包含)
     * @param r 右边界(包含)
     */
    public void quick_sort(int[] nums, int l, int r) {
        // 递归终止条件:区间无效(只有一个元素或空)
        if (l >= r) {
            return;
        }

        // 初始化左右指针
        int i = l; // 左指针,从左向右扫描
        int j = r; // 右指针,从右向左扫描

        // 选择基准值(pivot):取中间位置的元素,避免最坏情况(如已排序数组)
        // 使用 l + (r - l) / 2 防止整数溢出(等价于 (l + r) / 2,但更安全)
        int pivot = nums[l + (r - l) / 2];

        // 分区过程:将小于 pivot 的放左边,大于 pivot 的放右边
        while (i <= j) {
            // 从左边找到第一个 >= pivot 的元素
            while (nums[i] < pivot) {
                i++;
            }
            // 从右边找到第一个 <= pivot 的元素
            while (nums[j] > pivot) {
                j--;
            }
            
            // 如果两个指针未交错,说明找到了一对需要交换的元素
            if (i <= j) {
                // 交换 nums[i] 和 nums[j]
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                
                // 移动指针,继续扫描
                i++;
                j--;
            }
        }

        // 递归处理左右两个子区间
        // 注意:此时 j 是左半部分的右边界,i 是右半部分的左边界
        if (l < j) {
            quick_sort(nums, l, j);   // 排序左半部分 [l, j]
        }
        if (i < r) {
            quick_sort(nums, i, r);   // 排序右半部分 [i, r]
        }
    }
}
相关推荐
让我上个超影吧2 小时前
【力扣76】最小覆盖子串
算法·leetcode·职场和发展
近津薪荼2 小时前
优选算法——双指针5(单调性)
c++·学习·算法
2401_857683542 小时前
C++代码静态检测
开发语言·c++·算法
时艰.2 小时前
JVM 垃圾收集器(G1&ZGC)
java·jvm·算法
2401_838472512 小时前
内存泄漏自动检测系统
开发语言·c++·算法
m0_706653232 小时前
基于C++的爬虫框架
开发语言·c++·算法
diediedei3 小时前
嵌入式数据库C++集成
开发语言·c++·算法
君义_noip3 小时前
洛谷 P3388 【模板】割点(割顶)
c++·算法·图论·信息学奥赛·csp-s
xie0510_3 小时前
string模拟实现
开发语言·c++·算法