手摸手提桶跑路——LeetCode215. 数组中的第K个最大元素

121 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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]
}

微信截图_20220821000138.png

题是上午做出来的,offer 是下午丢的。

微信图片_20220727181614.jpg

解题思路——优先队列(最小堆)

这道题可以使用最小堆的方式去解。什么是最小堆呢?

简单来说,最小堆是一颗二叉树,任一非终端节点的数据值均不大于其左子节点和右子节点的值,也就是说越上面的节点值越小。

不是找第 k 大吗,怎么搞这么一出?我们仔细想想,如果我们维护一个长度为 k 数据结构,将最大值放在最后一个位置,第二大的放在倒数第二个,那么第 k 大的就是在第一个位置了。Javascript 中一般使用数组去模拟最小堆,对,没错,原生 Javascript 是没有最小堆这个东西的,所以接下来我们要手写一个了。

用数组表示二叉树大家都会吧?把根节点放在索引 0 的位置,左节点放在索引 1 的位置,右节点放在索引 2 的位置,那么对于任意一个索引为 index 的节点来说,其左节点的索引就是 (index + 1) * 2 - 1,右节点的索引为 (index + 1) * 2 ,父节点就是 (index - 1) >> 1

具体过程见下图:

最小堆_2.gif

题解

// 最小堆
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]
};

捕获.PNG