返回

数组中的第 K 个最大元素:剖析题目精髓,轻松寻找数组中的王者

前端

题目分析

给定一个整数数组 nums 和一个整数 k,要求返回数组中第 k 个最大的元素。需要注意的是,这里所说的第 k 个最大元素,指的是数组排序后的第 k 个最大元素,而不是第 k 个不同的元素。

解法一:快速选择

快速选择算法是一种非常高效的排序算法,它可以快速地找到数组中的第 k 个最大元素。算法的核心思想是将数组划分为两个部分,一部分包含比第 k 个最大元素大的元素,另一部分包含比第 k 个最大元素小的元素。然后,通过递归地应用快速选择算法,可以在线性时间内找到第 k 个最大元素。

步骤如下:

  1. 选择数组中的一个元素作为枢轴元。
  2. 将数组划分为两个部分,一部分包含比枢轴元大的元素,另一部分包含比枢轴元小的元素。
  3. 如果枢轴元恰好是第 k 个最大元素,则直接返回枢轴元。
  4. 如果枢轴元比第 k 个最大元素大,则在包含比枢轴元小的元素的部分继续搜索。
  5. 如果枢轴元比第 k 个最大元素小,则在包含比枢轴元大的元素的部分继续搜索。

代码示例:

def find_kth_largest(nums, k):
    """
    快速选择算法找到数组中的第 k 个最大元素。

    参数:
    nums: 输入的整数数组。
    k: 要找的第 k 个最大元素。

    返回:
    数组中第 k 个最大的元素。
    """

    def partition(nums, left, right):
        """
        对数组进行划分,返回枢轴元的位置。

        参数:
        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 quick_select(nums, left, right, k):
        """
        快速选择算法找到数组中的第 k 个最大元素。

        参数:
        nums: 输入的整数数组。
        left: 左边界。
        right: 右边界。
        k: 要找的第 k 个最大元素。

        返回:
        数组中第 k 个最大的元素。
        """

        if left == right:
            return nums[left]

        pivot_index = partition(nums, left, right)

        if pivot_index == k:
            return nums[pivot_index]
        elif pivot_index > k:
            return quick_select(nums, left, pivot_index - 1, k)
        else:
            return quick_select(nums, pivot_index + 1, right, k)

    if k <= 0 or k > len(nums):
        raise ValueError("k must be between 1 and the length of the array.")

    return quick_select(nums, 0, len(nums) - 1, k - 1)

时间复杂度:

快速选择算法的平均时间复杂度为 O(n),最坏情况下的时间复杂度为 O(n^2)。

空间复杂度:

快速选择算法的空间复杂度为 O(1)。

解法二:堆排序

堆排序是一种基于二叉堆的数据结构的排序算法。堆排序的思想是将数组中的元素构建成一个二叉堆,然后不断地从堆顶弹出元素,并将其插入到数组的尾部,直到堆为空。这样,数组中的元素就按照从大到小的顺序排列好了。

步骤如下:

  1. 将数组中的元素构建成一个二叉堆。
  2. 从堆顶弹出元素,并将其插入到数组的尾部。
  3. 重建二叉堆。
  4. 重复步骤 2 和步骤 3,直到堆为空。

代码示例:

def find_kth_largest(nums, k):
    """
    堆排序算法找到数组中的第 k 个最大元素。

    参数:
    nums: 输入的整数数组。
    k: 要找的第 k 个最大元素。

    返回:
    数组中第 k 个最大的元素。
    """

    def heapify(nums, n, i):
        """
        将数组中的元素构建成一个二叉堆。

        参数:
        nums: 输入的整数数组。
        n: 数组的长度。
        i: 当前节点的位置。
        """

        largest = i
        left = 2 * i + 1
        right = 2 * i + 2

        if left < n and nums[left] > nums[largest]:
            largest = left

        if right < n and nums[right] > nums[largest]:
            largest = right

        if largest != i:
            nums[i], nums[largest] = nums[largest], nums[i]
            heapify(nums, n, largest)

    def build_heap(nums):
        """
        将数组中的元素构建成一个二叉堆。

        参数:
        nums: 输入的整数数组。
        """

        n = len(nums)

        for i in range(n // 2 - 1, -1, -1):
            heapify(nums, n, i)

    def heap_sort(nums):
        """
        堆排序算法对数组进行排序。

        参数:
        nums: 输入的整数数组。
        """

        build_heap(nums)

        n = len(nums)

        for i in range(n - 1, 0, -1):
            nums[0], nums[i] = nums[i], nums[0]
            heapify(nums, i, 0)

    heap_sort(nums)

    return nums[k - 1]

时间复杂度:

堆排序算法的平均时间复杂度为 O(n log n),最坏情况下的时间复杂度为 O(n log n)。

空间复杂度:

堆排序算法的空间复杂度为 O(1)。

总结

快速选择算法和堆排序算法都是非常高效的算法,都可以用于找到数组中的第 k 个最大元素。快速选择算法的平均时间复杂度为 O(n),而堆排序算法的平均时间复杂度为 O(n log n)。在实际应用中,可以根据具体情况选择合适的算法。