这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战」
数组中的第K个最大元素 Kth largest element in an array
LeetCode传送门215. 数组中的第K个最大元素
题目
给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
Given an integer array nums and an integer k, return the largest element in the array.
Note that it is the largest element in the sorted order, not the distinct element.
Example:
Input: nums = [3,2,1,5,6,4], k = 2
Output: 5
Input: nums = [3,2,3,1,2,4,5,5,6], k = 4
Output: 4
Constraints:
- 1 <= k <= nums.length <=
思考线
解题思路
由于我们好久没有做使用堆排序来解决问题的题目,所以选择今天这道题,我们用堆排序来解决此问题。
由于JS没有内置的堆这种数据结构,所以我们手写一个Heap,具体代码在下面,我们在这里就不讲解了,之前的文章里面有详细的介绍, 不懂如何写堆排序的小伙伴可以点击进去看看。
有了堆之后我们做这道题的思路如下:
我们遍历数组,然后找到最大的k个元素,然后在这k个元素中,找到最小的元素即可。
根据以上想法来构建代码:
- 构建一个数据为空的
heap小顶堆, 同时遍历待查找数组 - 若
heap的size小于k,说明堆内的元素比较少,我们直接把当前元素放入堆内即可。 - 若
heap的size不小于k,说明堆内已经是有k个元素了,我们用peek方法,找到堆顶元素,把它和nums[i]进行比较:- 如果其小于
num[i], 把堆顶元素删除,同时把nuns[i]放入堆内 - 如果大于
nums[i], 我们不做任何处理即可。
- 如果其小于
- 最后
heap的堆顶元素即是我们想要的结果。
具体代码如下:
function findKthLargest(nums: number[], k: number): number {
const heap = new Heap([], (a, b) => b - a > 0);
const len = nums.length;
for (let i = 0; i < len; i++) {
if (heap.size() < k) {
heap.offer(nums[i])
} else {
const min = heap.peek();
if (min < nums[i]) {
heap.poll()
heap.offer(nums[i])
}
}
}
return heap.peek()
};
class Heap {
data: number[]
comparer: (a: number, b: number) => boolean
constructor(data: number[] = [], comparer: (a: number, b: number) => boolean = (a, b) => a - b > 0) {
this.data = data
this.comparer = comparer;
this.heapify()
}
heapify() {
const len = this.size()
for (let i = 1; i < len; i++) {
this.bubbleUp(i);
}
}
bubbleUp(index: number) {
while (index > 0) {
const parent = (index - 1) >> 1;
if (this.comparer(this.data[index], this.data[parent])) {
this.swap(parent, index);
index = parent
} else {
break;
}
}
}
peek() {
return this.data[0];
}
offer(val: number) {
const size = this.size()
this.data.push(val);
this.bubbleUp(size)
}
poll() {
if (this.size() === 0) return null;
if (this.size() === 1) return this.data.pop()
const res = this.data[0];
this.data[0] = this.data.pop();
this.bubbleDown(0);
return res;
}
bubbleDown(index) {
const len = this.size();
while (index < len) {
const left = index * 2 + 1;
const right = index * 2 + 2;
let findIndex = index;
if (left < len && this.comparer(this.data[left], this.data[findIndex])) {
findIndex = left
}
if (right < len && this.comparer(this.data[right], this.data[findIndex])) {
findIndex = right
}
if (findIndex !== index) {
this.swap(findIndex, index);
index = findIndex
} else {
break;
}
}
}
size() {
return this.data.length
}
swap(ind1: number, ind2: number) {
[this.data[ind1], this.data[ind2]] = [this.data[ind2], this.data[ind1]];
}
}
时间复杂度
O(nlogn): 由于遍历的的时间复杂度为n,同时在堆排序过程中的时间复杂度为logn,所以最坏的情况为nlogn
总结
类似的题,我们已经做了很多道,今天再拿出这道题来做是因为,堆排序相对比较复杂,还是要多多练习的。今天写堆排序的时候还是细节的地方出了点小错误,半小时才写出Heap类。还是要多加练习。
这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。