📜  资质 |门 CS 1998 |第 56 题(1)

📅  最后修改于: 2023-12-03 15:28:13.472000             🧑  作者: Mango

资质 |门 CS 1998 |第 56 题

题目简介

这是门 CS 1998 年的第 56 题,要求程序员实现一个函数,给定一组只包含数字的数组,输出其中第 k 大的元素。

函数介绍
def find_kth_largest(nums: List[int], k: int) -> int:
    pass
输入
  • nums: List[int]:包含数字的数组。
  • k: int:要求输出的第 k 大的元素。
输出
  • int:数组中第 k 大的元素。
算法思路

该问题可以通过排序后直接找到第 k 大的元素,但是时间复杂度为 $O(n\log n)$, 当数组较大时性能较低。为了提升性能,有两种优化思路:

思路一:快速选择算法

快速选择(Quickselect)是一种在无序列表中查找第 k 大(或第 k 小)元素的选择算法。该算法的时间复杂度为 $O(n)$,比快速排序的期望运行时间 $O(n\log n)$ 更优,而且实现简单。

具体实现参考:https://www.geeksforgeeks.org/quickselect-algorithm/

思路二:堆排序算法

堆排序算法是一种通过构建最大堆(或最小堆)实现排序的算法。在该问题中,可以使用一个最小堆来存储数组元素,堆的大小为 k,遍历数组将元素依次加入堆中。当堆的大小超过 k 时,将堆顶的元素弹出,保证最终堆的大小为 k,堆顶元素即为第 k 大的元素。时间复杂度为 $O(n\log k)$。

具体实现参考:https://www.geeksforgeeks.org/kth-largest-element-in-an-array/

算法分析

两种算法的时间复杂度不同,快速选择算法在最差情况下的时间复杂度为 $O(n^2)$,但在平均情况下的时间复杂度为 $O(n)$,实现相对简单;堆排序算法的时间复杂度最坏为 $O(n\log k)$,可以对数组进行预处理,空间复杂度较高。

当数组较大时,我们推荐使用堆排序算法,当数组较小时,可以选择快速选择算法。

示例代码
import heapq
from typing import List

# 方法一:快速选择算法
def find_kth_largest_quickselect(nums: List[int], k: int) -> int:
    def partition(left, right, pivot_idx):
        pivot = nums[pivot_idx]
        # Move pivot to right
        nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx]  
        store_idx = left
        # Move elements smaller than pivot to left
        for i in range(left, right):
            if nums[i] < pivot:
                nums[store_idx], nums[i] = nums[i], nums[store_idx]
                store_idx += 1
        # Move pivot where it belongs
        nums[right], nums[store_idx] = nums[store_idx], nums[right]
        return store_idx

    def select(left, right, k_smallest):
        if left == right:
            return nums[left]
        pivot_idx = random.randint(left, right)          
        pivot_idx = partition(left, right, pivot_idx)
        if k_smallest == pivot_idx:
            return nums[k_smallest]
        elif k_smallest < pivot_idx:
            return select(left, pivot_idx - 1, k_smallest)
        else:
            return select(pivot_idx + 1, right, k_smallest)

    return select(0, len(nums) - 1, len(nums) - k)


# 方法二:堆排序算法
def find_kth_largest_heapq(nums: List[int], k: int) -> int:
    heap = []
    for num in nums:
        heapq.heappush(heap, num)
        if len(heap) > k:
            heapq.heappop(heap)
    return heap[0]
参考链接