📌  相关文章
📜  未排序数组中第K个最小最大元素|设置2(预期线性时间)(1)

📅  最后修改于: 2023-12-03 14:55:26.272000             🧑  作者: Mango

找到未排序数组中第K个最小/最大元素

问题描述

给定一个未排序的数组,需要找到其中第K个最小或最大的元素。例如,给定数组 [3, 7, 2, 1, 8, 6, 5, 4],需要找到其中第3个最小的元素,值为 3。

解决方案
方法一:排序

最简单的解决方案是先对数组进行排序,然后直接找到第K个元素。这个算法的时间复杂度为 $O(n \log n)$,其中 $n$ 为数组的长度。

方法二:快速选择

我们可以使用快速排序中的 partition() 方法来找到数组中第K个最小(或最大)的元素。该方法的时间复杂度为 $O(n)$,其中 $n$ 为数组的长度。假设我们要找到第K个最小的元素。

  1. 使用 partition() 方法来将数组划分成小于等于 K 的一部分以及大于 K 的一部分。
  2. 如果第K个元素在小于等于 K 的一部分中,那么我们继续对小于等于 K 的一部分进行 partition() 操作。
  3. 如果第K个元素在大于 K 的一部分中,那么我们继续对大于 K 的一部分进行 partition() 操作。
  4. 重复步骤 1 到 3,直到找到第K个最小的元素为止。

因为每次将数组划分为两部分,所以算法的时间复杂度为 $O(n)$,其中 $n$ 为数组的长度。

代码示例

def partition(nums, left, right):
    pivot = nums[right]
    i = left - 1
    
    for j in range(left, right):
        if nums[j] < pivot:
            i += 1
            nums[i], nums[j] = nums[j], nums[i]
    
    nums[i+1], nums[right] = nums[right], nums[i+1]
    
    return i+1

def kthSmallest(nums, k):
    left, right = 0, len(nums)-1
    
    while True:
        pivot_index = partition(nums, left, right)
        
        if pivot_index == k-1:
            return nums[pivot_index]
        elif pivot_index < k-1:
            left = pivot_index + 1
        else:
            right = pivot_index - 1
方法三:堆

我们可以使用一个大小为K的最大堆来解决这个问题。我们遍历一遍数组,将每个元素加入堆中,如果堆的大小超过K,则移除堆顶元素。遍历结束后堆顶元素即为第K个最小的元素。该方法的时间复杂度为 $O(n \log k)$,其中 $n$ 为数组的长度。

同理,如果要找到第K个最大的元素,我们可以使用一个大小为K的最小堆。

代码示例

import heapq

def kthSmallest(nums, k):
    heap = []
    
    for num in nums:
        heapq.heappush(heap, -num)
        if len(heap) > k:
            heapq.heappop(heap)
    
    return -heap[0]
总结

我们介绍了三种方法来找到未排序数组中的第K个最小或最大元素:排序、快速选择和堆。其中,快速选择和堆的时间复杂度都为 $O(n)$ 或 $O(n\log k)$,要比排序的时间复杂度 $O(n \log n)$ 更优秀。在实际问题中,我们可以根据具体情况来选择哪种方法。