[路飞]_每天刷leetcode_75(数组中的第K个最大元素)

143 阅读2分钟

这是我参与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 kthk^{th} largest element in the array.

Note that it is the kthk^{th} largest element in the sorted order, not the kthk^{th} 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 <= 10410^4
  • 104<=nums[i]<=104-10^4 <= nums[i] <= 10^4

思考线


解题思路

由于我们好久没有做使用堆排序来解决问题的题目,所以选择今天这道题,我们用堆排序来解决此问题。

由于JS没有内置的堆这种数据结构,所以我们手写一个Heap,具体代码在下面,我们在这里就不讲解了,之前的文章里面有详细的介绍, 不懂如何写堆排序的小伙伴可以点击进去看看。

有了堆之后我们做这道题的思路如下: 我们遍历数组,然后找到最大的k个元素,然后在这k个元素中,找到最小的元素即可。

根据以上想法来构建代码:

  1. 构建一个数据为空的heap小顶堆, 同时遍历待查找数组
  2. heapsize小于k,说明堆内的元素比较少,我们直接把当前元素放入堆内即可。
  3. heapsize 不小于k,说明堆内已经是有k个元素了,我们用peek方法,找到堆顶元素,把它和nums[i]进行比较:
    • 如果其小于num[i], 把堆顶元素删除,同时把nuns[i]放入堆内
    • 如果大于nums[i], 我们不做任何处理即可。
  4. 最后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类。还是要多加练习。

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。