持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
每日刷题 2022.10.10
- leetcode原题链接:leetcode.cn/problems/kt…
- 难度:中等
- 解法:快速选择
题目
- 给定整数数组 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 <= 10^5
-10^4 <= nums[i] <= 10^4
解题思路
- 根据题意可知:需要求数组中的第k个最大元素,而不是第k个不同的元素,也就是多个重复相同的数字也会被计算进去。
- 题目中还要求,需要使用时间复杂度
o(n)
。那么就想到了使用优先队列priorityQueue
,可以先遍历整个数组一遍,将所有的数依次压入到priorityQueue
中,最后再依次从中取k
次,那么就获得了第k
个最大元素。
思考
- 全部
n
个数可能有很大,想要直接全部存储下来,不太可能。 - 优化方法一:因此优先队列中并不需要将所有的数全部存储下来,很多都是废数,我们只需要第
k
个。当超过k
个之后,和队列顶端的元素对比,小于就不需要存入,大于存入。 - 优化方法二:使用快速选择,因为我们并不是很关注整个数组排序后的顺序是什么样的,而我们更关心的是数组中的第
k
个元素是谁,第k
个之前和之后的都是哪些数都不关心。可以使用快速选择,将小于的放在prviot
的前面,大于放在prviot
的后面就可以啦
AC
代码
var findKthLargest = function(num, k) {
let nums = [...num];
let n = nums.length;
return qselect(0, n - 1, n - k);
function swap (x, y) {
let t = nums[x];
nums[x] = nums[y];
nums[y] = t;
}
function qselect(l, r, k) {
// 左右的区间都已经安排好,才会只剩下一个元素
// console.log(l, r, nums[k])
if(l === r) return nums[k];
// 主要用于边界处理
let i = l - 1, j = r + 1, x = nums[l];
while(i < j) {
// i的左边表示全部小于 基数 的元素
do i++; while(nums[i] < x);
// j的右边表示全部大于 基数 的元素
do j--; while(nums[j] > x);
// 两个数值之间存在不符合的,需要交换位置
if(i < j) swap(i, j);
// console.log('process::', i,j, k)
}
// console.log('end:::', k, j)
// 需要完之间的所有元素,判断 需要接着遍历左边的 还是 右边的部分
if(k <= j) return qselect(l, j, k);
else return qselect(j + 1, r, k);
}
};