📅  最后修改于: 2023-12-03 15:28:13.472000             🧑  作者: Mango
这是门 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]