📜  资质|算术能力4 |问题5(1)

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

资质 | 算术能力 4 | 问题 5

介绍

资质 | 算术能力 4 | 问题 5 是 LeetCode 上的一道经典算法题目。本题要求编写程序,在一个未排序的整数数组中找到第 k 个最大的元素。此题考察了算法的时间复杂度和空间复杂度。

题目

给定整数数组 nums 和整数 k,请编写程序在 nums 中找到第 k 个最大的元素。

说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组长度。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
解法

本题的解法有很多,可用的算法包括快速排序、堆排序、冒泡排序等等。在这里,我们介绍一种时间复杂度为 O(nlogn) 的解法——快速排序。(堆排序的时间复杂度也为 O(nlogn),但堆排序的实现通常更为复杂)

快速排序的算法思想是分治法。它从数组中取出一个数作为基准数(pivot,通常选最后一个元素),将数组中所有小于基准数的数放在其左边,所有大于基准数的数放在其右边,再对左右两个子数组递归调用快速排序函数。

具体实现过程如下:

  1. 取一个基准数 pivot,将数组分成左右两部分。
  2. 比较数组中的元素与基准数,将小于基准数的元素放在左边,大于等于基准数的元素放在右边。
  3. 递归地对左右两个子数组进行快速排序。

解法的核心是将数组中小于基准数的元素移到左边,大于等于基准数的元素移到右边。这可以通过双指针的方式实现。具体解法如下:

  1. 初始化 i 和 j 两个指针,分别指向数组的第一个和最后一个元素。
  2. 从左到右,遍历数组中的元素,找到第一个大于等于基准数的元素。
  3. 从右到左,遍历数组中的元素,找到第一个小于基准数的元素。
  4. 如果 i < j,交换 nums[i] 和 nums[j]。
  5. 重复 2~4 步,直到 i >= j。
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        quickSort(nums, 0, nums.size() - 1);
        return nums[nums.size() - k];
    }

    void quickSort(vector<int>& nums, int left, int right) {
        if (left >= right) return;

        int pivot = nums[right];
        int i = left, j = right;

        while (i < j) {
            while (i < j && nums[i] < pivot) i++;
            while (i < j && nums[j] >= pivot) j--;
            if (i < j) swap(nums[i], nums[j]);
        }

        swap(nums[i], nums[right]);

        quickSort(nums, left, i - 1);
        quickSort(nums, i + 1, right);
    }
};
总结

本题考察了算法的时间复杂度和空间复杂度。快速排序的时间复杂度为 O(nlogn),空间复杂度为 O(logn)。本题需要找到第 k 个最大的元素,因此需要将整个数组排序后才能得到该元素,因此时间复杂度最好也为 O(nlogn)。因此本题解法的时间复杂度已经达到了最优解。

参考链接