每日一题:找出数组中第 k 大的元素

文章介绍了快速选择算法,这是一种基于快速排序思想的算法,用于在数组中找到第k大的元素。通过随机选择基准元素并进行分区,算法在平均情况下具有O(n)的时间复杂度。文章提供了Python代码实现,并展示了测试用例。
摘要由CSDN通过智能技术生成

解题思路:

  1. 使用快速选择算法来找出第 k 大的元素。快速选择算法基于快速排序的思想,通过每次选取一个基准元素将数组划分为两部分,然后只在其中一部分继续查找,从而快速定位第 k 大的元素。
  2. 选择一个基准元素,可以随机选择数组中的一个元素作为基准。
  3. 使用分区函数将数组划分为两部分:小于基准元素的部分和大于等于基准元素的部分。
  4. 比较划分后基准元素所在的位置 pivot_index 与目标位置 k 的关系:
  • 如果 pivot_index == k - 1,则找到了第 k 大的元素,返回基准元素。
  • 如果 pivot_index > k - 1,则目标元素在基准元素的左侧,继续在左侧部分进行查找。
  • 如果 pivot_index < k - 1,则目标元素在基准元素的右侧,继续在右侧部分进行查找。
  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)。但由于基准元素的随机选择,最坏情况的出现概率较低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值