📅  最后修改于: 2023-12-03 15:10:39.840000             🧑  作者: Mango
在现实生活中,我们经常需要在一个未排序的数组中搜索第k个最小或最大的元素。最简单的方法可能是对数组进行排序并返回第k个元素,但这种方法的时间复杂度为O(nlogn),并不够高效。该主题将介绍如何以O(n)的时间复杂度实现该目标。
该解题主要是利用快速选择(QuickSelect)的思想。快速选择是快速排序的变体,它基于分治算法。该算法通过单次快排将数组的第k个元素移到正确的位置上。快速选择的时间复杂度为O(n),因为在任何一次递归中,我们都只需要对一个子数组进行操作。
在快速排序中,我们选择一个随机数作为基准元素,称为主元(Pivot)。我们将数组分为两部分,其中一部分所有元素都小于等于主元,而另一部分所有元素都大于主元。此时,主元的位置已经确定,我们可以将该位置与k进行比较:
最终,当我们找到第k个元素时,我们可以将其返回即可。
下面是以Python语言实现的快速选择算法:
def partition(nums, left, right, pivot_index):
pivot = nums[pivot_index]
nums[right], nums[pivot_index] = nums[pivot_index], nums[right]
idx = left
for i in range(left, right):
if nums[i] < pivot:
nums[idx], nums[i] = nums[i], nums[idx]
idx += 1
nums[right], nums[idx] = nums[idx], nums[right]
return idx
def quick_select(nums, left, right, target):
if left == right:
return nums[left]
pivot_index = left + (right - left) // 2
pivot_index = partition(nums, left, right, pivot_index)
if target == pivot_index:
return nums[target]
elif target < pivot_index:
return quick_select(nums, left, pivot_index - 1, target)
else:
return quick_select(nums, pivot_index + 1, right, target)
def kth_smallest(nums, k):
return quick_select(nums, 0, len(nums) - 1, k - 1)
def kth_largest(nums, k):
return quick_select(nums, 0, len(nums) - 1, len(nums) - k)
我们先介绍partition
函数。该函数实现了快速排序中的分区(partition)操作,将数组中的元素分为两个部分。具体而言:
然后,我们介绍quick_select
函数。该函数实现了快速选择的核心逻辑。该函数会在任意一个子数组中选择一个主元,并将数组分为两个部分。如果这个主元恰好就是我们找寻的元素,则函数返回该元素。否则,如果我们需要的元素在主元的左侧,则递归处理主元左侧的数组。如果需要的元素在主元的右侧,则递归处理主元右侧的数组。
最后,我们介绍kth_smallest
和kth_largest
函数。这两个函数分别用于查找数组中第k个最小和最大的元素。它们都是调用quick_select
函数,并将目标索引降低1来适应0-based的数组下标。
在本文中,我们介绍了未排序数组中查找第k个最小或最大元素的算法。我们介绍了快速选择算法的原理,并给出了实现方式。与其它最优解一样,快速选择的时间复杂度为O(n)。