【LeetCode】215. 数组中的第K个最大元素

题目描述

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

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

示例 2:

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

提示:

1 <= k <= nums.length <= 105
-104 <= nums[i] <= 104

方法一:优秀解法 – 快排+随机化

class Solution {
public:
    void QuickPartition(vector<int>& nums, int start, int end, int target){
        // 随机取一个数
        srand(time(nullptr));
        int random = rand() % (end - start + 1) + start;
        int base = nums[random];
        // 将这个数放到数组的开头位置
        swap(nums[start], nums[random]);
        int index = start;
        // 从待排区间的第一个元素开始,依次与随机选择的元素base比较
        // 如果大于等于base,就把该元素交换到index+1的位置,index++
        // 最终,下标小于index的元素都比base大
        for(int i = start+1; i <= end; i++){
            if(nums[i] >= base){
                swap(nums[i], nums[index+1]);
                index++;
            }
        }
        // base存放在数组最开始的位置,将其交换到index位置上
        // 它前面的元素都比本身大
        swap(nums[index], nums[start]);
        // 如果index恰好等于target,那么就结束函数调用,不会继续迭代
        // index比target大,那就在index的左边继续查找
        if(index > target) QuickPartition(nums, start, index-1, target);
        // index比target小,那就在index的右边继续查找
        else if(index < target) QuickPartition(nums, index+1, end, target); 
    }
    int findKthLargest(vector<int>& nums, int k) {
        // 快排思想+随机化
        // 快排是一次找出一个数的正确位置,使得左边的数都比他大,
        // 右边的数都比他小,返回下标为k-1的值
        QuickPartition(nums, 0, nums.size() - 1, k - 1);
        return nums[k - 1];
    }
};

心得

  • 总体思路: 这一题主要就是对数组进行降序排序,返回第k个位置,也就是下标为k-1的元素。常规排序解法时间复杂度都在O(n2),难点在于如何满足O(n2)的时间复杂度。
  • 解法:快排+随机化
    快排的平均时间复杂度为O(n logn),因此需要对快排进行优化。首先,回顾一下快速排序
    1.分解 :将数组arr[left,…,right]划分为两个子数组arr[left,…,q-1]和arr[q+1, …, right],使得第一个子数组的所有元素都小于arr[q],第二个子数组的所有元素都大于arr[q]。
    在分解这个步骤,也还有很多方式,除了本文的顺序遍历,还有“填坑法”,放在参考文献。
    2.解决:通过递归调用快排,对子数组进行排序。
    3.合并:因为子数组都是原址排序,所以不需要进行合并操作,arr[left, …, right]已经有序。
    可以发现,在快排操作中,每进行一次划分都可以确定一个元素的最终位置。所以只要某次划分的q下标为k-1时,我们就找到了答案。
    因此,我们可以对快排进行优化来解决这个问题,快排性能和划分出的子数组长度密切相关,可以引入随机化来加速快排,它的时间代价的期望为O(n),证明略。
  • 这道题还可以用堆排序,涉及大根堆小根堆,今日所学的知识超标,这个知识点放到以后再学。

在这里插入图片描述

参考文献
[1]『 TopK问题 』快速排序、堆排序详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值