Skip to main content

数组中的第-k-个最大元素

题目

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

示例

输入: [3, 2, 1, 5, 6, 4] 和 k = 2

输出: 5

题解

我们在快速排序中了解到了 partition 函数, 它是用来找每个子区间的分界点 p, 以保证分界点的左侧都小于 p, 右边的都大于 p. 题目要求的是第 k 个最大元素, 这个元素其实就是 nums 升序排序后索引为 nums.length - k 的元素.

/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function (nums, k) {
const n = nums.length
return quickselect(nums, 0, n - 1, n - k) // 调用 quickselect 寻找第 n-k 小的元素
}

/**
* 快速选择算法, 找到第 k 大的元素
* @param {number[]} nums - 输入的数组
* @param {number} l - 当前搜索范围的左边界
* @param {number} r - 当前搜索范围的右边界
* @param {number} k - 目标元素的索引(从 0 开始)
* @return {number} - 数组中第 k 大的元素
*/
function quickselect(nums, l, r, k) {
if (l === r) return nums[k] // 递归终止条件, 找到第 k 大的元素

const x = nums[l] // 选择第一个元素作为枢轴
let i = l - 1,
j = r + 1

// 快速排序的划分过程
while (i < j) {
do i++
while (nums[i] < x) // 找到大于等于枢轴的元素
do j--
while (nums[j] > x) // 找到小于等于枢轴的元素

// 交换 nums[i] 和 nums[j]
if (i < j) {
;[nums[i], nums[j]] = [nums[j], nums[i]]
}
}

// 递归查找, 确定第 k 大元素的位置
if (k <= j) {
return quickselect(nums, l, j, k) // 第 k 大元素在左边
} else {
return quickselect(nums, j + 1, r, k) // 第 k 大元素在右边
}
}