leetcode:215.无序数组中找第k大的元素

题目来源

题目描述

在这里插入图片描述

题目解析

快排

原数组是要求第k大的问题可以转换为求第size - k + 1小的问题

思路

  • 无序数组中随机选择一个数V,然后对V对整个数组做荷兰国旗问题。此后,<V的在左边,=V的在中间,>V的在右边
  • 如果命中就停,如果没有命中,然后根据实际选择左侧或者右侧回到第一步
  • 时间复杂度O(N)

动画

实现


class Solution {
    std::vector<int> partition(std::vector<int>& arr, int L, int R, int prio){
        int less = L - 1, more = R + 1, curr = L;
        while (curr < more){
            if(arr[curr] < prio){
                std::swap(arr[++less], arr[curr++]);
            }else if(arr[curr] > prio){
                std::swap(arr[curr], arr[--more]);
            }else{
                curr++;
            }
        }
        return {less + 1, more - 1};
    }

    // arr[L..R]  范围上,如果排序的话(不是真的去排序),找位于index的数
    int process(std::vector<int> arr, int L, int R, int index){
        if(L == R){  //
            return arr[L];
        }

        int pivot = arr[rand() % (R - L + 1) + L];
        auto range = partition(arr, L, R, pivot);
        if (index >= range[0] && index <= range[1]) {  // 要找的索引刚好是要求的索引
            return arr[index];
        } else if (index < range[0]) {
            return process(arr, L, range[0] - 1, index);
        } else {
            return process(arr, range[1] + 1, R, index);
        }
    }
public:
    int findKthLargest(vector<int> &nums, int k){
        srand(time(0));
        int result = 0;
        int numsSize = int(nums.size());
        if (numsSize == 0 || k > numsSize)
        {
            return 0;
        }
        //寻找第kMIN小的数
        int kMin = numsSize - k + 1; //第k小
        result = process(nums, 0, numsSize - 1, kMin - 1); // 第kMin小的元素对应的索引在kMin
        return result;
    }
};

也可以从大到小排序,这样就不用转换为第kMin小了

优先级队列

思路

  • 唯一一个长度为k的小根堆,保持队列中的元素时钟为k个
  • 遍历数组nums,入队一个元素之后,立即弹出堆顶最小的元素
  • 遍历完成之后,堆顶的元素就是第k大的数字

ps:求第k大的数用小根堆,求第k小的数用大根堆

时间复杂度O(N*logK)

什么时候用?

在数据量很大的时候,可以实现「在线算法」,不用一下子把所有数据读入内存。

实现

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k)  {
       // 维护一个小顶堆
        std::priority_queue<int, std::vector<int>, std::greater<int>> q;
        int len = nums.size();
        for (int i = 0; i < len; ++i) {
            q.push(nums[i]);
            if(q.size() > k){
                q.pop();
            }
        }
        return q.top();
    }
};
class Solution {
public:
    int findKthLargest(vector<int> &arr, int k){
    	  // 维护一个小顶堆
        std::priority_queue<int , std::vector<int>, std::greater<>> minheap;
        for (int i = 0; i < k; ++i) {
            minheap.push(arr[i]);
        }

        for (int i = k; i < arr.size(); ++i) {
            if(arr[i] < minheap.top()){
                minheap.pop();
                minheap.push(arr[i]);
            }
        }

        return minheap.top();
    }
};
class Solution {
  
public:
    int findKthLargest(vector<int>& nums, int k) {
        // 大根堆
        std::priority_queue<int> q(nums.begin(), nums.end());
        for (int i = 0; i < k - 1; ++i) {
            q.pop();
        }
        return q.top();
    }
};

调用库函数

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        std::sort(nums.begin(), nums.end());
        return nums[nums.size() - k];
    }
};
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return sort(nums.begin(), nums.end(), greater<int>()), nums[k - 1];
    }
};

类似题目

题目思路
leetcode:215. 无序数组中第k大的元素(排序后位于第n-k索引上的数) Kth Largest Element in an Array 先算出第k大的元素应该在排序后的索引,然后快排取数
leetcode:703. 数据流中的第 K 大元素 Kth Largest Element in a Stream要求第k大,但是因为是数据流,所以无法快排,因此维护一个k长度的小根堆
leetcode:面试题 17.14. 最小K个数 smallest-k-lcci要求最小的用大根堆;快速排序取数
leetcode:347. 无序数组中前 K 个高频元素 Top K Frequent Elements
leetcode:414. 无序数组中第3大的数(第三个不同的数) Third Maximum Number 注意,相同的数只计算一次,因此不用优先队列和快速排序。可以维护一个长度为3的set,或者维护a、b、c三个变量
leetcode:973. 最接近原点的 K 个点. K Closest Points to Origin
leetcode:378. 有序矩阵中第 K 小的元素二分,N路归并
leetcode:440. 字典序的第K小数字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值