携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,点击查看活动详情
题目描述
给定整数数组 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
解题思路——排序
题目要求我们求出数组中的第 k 大元素,比如 [1,1,2,2] 中, 第二大的还是 1,而不是 2,也就是说相同的数字不是以并列的形式排名,而是按顺序往后排。
理解了思路之后我们来解题,既然要求的是第 k 大元素,那么直接降序排序后取数组下标为 k - 1 的元素输出就完事了。
题解
let findKthLargest = function(nums, k){
return nums.sort((a,b)=>b-a)[k-1]
}
题是上午做出来的,offer 是下午丢的。
解题思路——优先队列(最小堆)
这道题可以使用最小堆的方式去解。什么是最小堆呢?
简单来说,最小堆是一颗二叉树,任一非终端节点的数据值均不大于其左子节点和右子节点的值,也就是说越上面的节点值越小。
不是找第 k 大吗,怎么搞这么一出?我们仔细想想,如果我们维护一个长度为 k 数据结构,将最大值放在最后一个位置,第二大的放在倒数第二个,那么第 k 大的就是在第一个位置了。Javascript 中一般使用数组去模拟最小堆,对,没错,原生 Javascript 是没有最小堆这个东西的,所以接下来我们要手写一个了。
用数组表示二叉树大家都会吧?把根节点放在索引 0 的位置,左节点放在索引 1 的位置,右节点放在索引 2 的位置,那么对于任意一个索引为 index 的节点来说,其左节点的索引就是 (index + 1) * 2 - 1,右节点的索引为 (index + 1) * 2 ,父节点就是 (index - 1) >> 1。
具体过程见下图:
题解
// 最小堆
class MinHeap {
heap = []
swap (index1, index2) {
let temp = this.heap[index1]
this.heap[index1] = this.heap[index2]
this.heap[index2] = temp
}
getLeftNode(index) {
return (index + 1) * 2 - 1
}
getRightNode(index) {
return (index + 1) * 2
}
getParentNode(index) {
if(index === 0)
return undefined
return (index - 1) >> 1
}
// 向上移动
shiftUp(index) {
let parentIndex = this.getParentNode(index)
if(index != 0 && (this.heap[parentIndex] > this.heap[index] )) {
this.swap(parentIndex, index)
this.shiftUp(parentIndex)
}
}
// 向下
shitDown(index) {
let rightIndex = this.getRightNode(index),
leftIndex = this.getLeftNode(index)
if(leftIndex < this.heap.length && (this.heap[leftIndex] < this.heap[index])) {
this.swap(index, leftIndex)
this.shitDown(leftIndex)
}
if(rightIndex < this.heap.length && (this.heap[rightIndex] < this.heap[index])) {
this.swap(rightIndex, index)
this.shitDown(rightIndex)
}
}
insert(value) {
this.heap.push(value)
this.shiftUp(this.heap.length - 1)
}
}
var findKthLargest = function(nums, k) {
let arr = new MinHeap()
for(let i = 0 ; i < nums.length; i++) {
if(i < k) {
arr.insert(nums[i])
}else{
if (nums[i] >= arr.heap[0]) {
arr.heap[0] = nums[i]
arr.shitDown(0)
}
}
}
return arr.heap[0]
};