解题思路:
- 使用快速选择算法来找出第 k 大的元素。快速选择算法基于快速排序的思想,通过每次选取一个基准元素将数组划分为两部分,然后只在其中一部分继续查找,从而快速定位第 k 大的元素。
- 选择一个基准元素,可以随机选择数组中的一个元素作为基准。
- 使用分区函数将数组划分为两部分:小于基准元素的部分和大于等于基准元素的部分。
- 比较划分后基准元素所在的位置 pivot_index 与目标位置 k 的关系:
- 如果 pivot_index == k - 1,则找到了第 k 大的元素,返回基准元素。
- 如果 pivot_index > k - 1,则目标元素在基准元素的左侧,继续在左侧部分进行查找。
- 如果 pivot_index < k - 1,则目标元素在基准元素的右侧,继续在右侧部分进行查找。
- 重复步骤 2~4,直到找到第 k 大的元素。
代码实现及注释:
import random
def partition(nums, low, high):
# 选择随机基准元素
pivot_index = random.randint(low, high)
pivot = nums[pivot_index]
# 将基准元素移动到末尾
nums[pivot_index], nums[high] = nums[high], nums[pivot_index]
# 分区过程
i = low # i 用于记录小于基准元素的区域边界
for j in range(low, high):
if nums[j] >= pivot:
nums[i], nums[j] = nums[j], nums[i]
i += 1
# 将基准元素放到正确的位置上
nums[i], nums[high] = nums[high], nums[i]
return i
def quick_select(nums, low, high, k):
if low == high:
# 只有一个元素
return nums[low]
# 分区操作
pivot_index = partition(nums, low, high)
if pivot_index == k - 1:
# 找到第 k 大的元素
return nums[pivot_index]
elif pivot_index > k - 1:
# 目标元素在基准元素的左侧
return quick_select(nums, low, pivot_index - 1, k)
else:
# 目标元素在基准元素的右侧
return quick_select(nums, pivot_index + 1, high, k)
def find_kth_largest(nums, k):
return quick_select(nums, 0, len(nums) - 1, k)
# 测试
nums = [3, 2, 1, 5, 6, 4]
k = 2
result = find_kth_largest(nums, k)
print(result) # 输出: 5,因为数组中第 2 大的元素是 5
nums = [3, 2, 1, 5, 6, 4]
k = 4
result = find_kth_largest(nums, k)
print(result) # 输出: 3,因为数组中第 4 大的元素是 3
该算法的平均时间复杂度为 O(n),其中 n 是数组的长度。在快速选择算法中,每次选取一个基准元素进行分区,每次分区的时间复杂度为 O(n)。在平均情况下,每次分区可以将数组划分为大小接近一半的两个部分,因此平均需要递归 log(n) 次。因此,总的平均时间复杂度为 O(n + log(n)),近似于 O(n)。在最坏情况下,如果每次分区的基准元素都是当前数组中的最小或最大元素,算法的时间复杂度将退化为 O(n^2)。但由于基准元素的随机选择,最坏情况的出现概率较低。