215.数组中的第K个最大元素 | 347.前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

思路一:优先队列(小根堆)

【c++】STL里的priority_queue用法总结_小拳头的博客-CSDN博客_priority_queue头文件

priority_queue<int,vector<int>,greater<int>> p;

优先队列默认为大根堆,priority_queue<int> p等于priority_queue<int,vector<int>,less<int>> p

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
        priority_queue<int,vector<int>,greater<int>> p;
        for(int i=0;i<nums.size();i++)//所有元素都进一次小根堆
        {
            p.push(nums[i]);
            if(i>=k)//如果元素个数大于等于k,就把小根堆的堆顶元素(最小值)出出去
            {
                p.pop();
            }
        }
        int res=p.top();//此时小根堆有k个元素,堆顶的元素就是第k个最大的元素
        return res;
    }
};

思路二:快速选择算法(循环,不是递归)

快速选择算法是快速排序的变体。第 k 个最大的元素,相当于数组升序排序的下标为 n - k 的元素(第n-k+1个元素)。

在快速排序算法 partition 函数执行时,会将 nums[p] 排到正确的位置,使得 nums[low..p-1] < nums[p] < nums[p+1..high],此时就知道 nums[p] 的排名了。

那么我们可以把 p 和 n-k 进行比较,如果 p < n-k 说明要找的元素在 nums[p+1..high] 中,如果 p > n-k 说明要找的元素在 nums[low..p-1] 中

然后,去 nums[p+1..high] 或者 nums[lo..p-1] 这两个子数组中执行 partition 函数,就可以进一步缩小范围,最终找到目标元素。

时间复杂度:O(N),不断循环,缩小范围,找到第k个最大的元素。

class Solution 
{
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
        srand(time(NULL));//设置随机种子
        random_shuffle(nums.begin(),nums.end());//使用random_shuffle需要先设置随机种子
        int n = nums.size();
        int low = 0;
        int high = n - 1;
        while (low<=high)//不断缩小范围
        {
            int p = partition(nums,low,high);
            if (p == n-k)
                return nums[p];
            else if (p < n-k)
                low = p + 1;
            else    
                high = p - 1;
        }
        return -1;
    }

    //----左右交换
    int partition(vector<int> & nums, int low, int high)//同快速排序的partition函数
    {
        int pivot = nums[low];
        int i=low+1;
        int j=high;
        while (i<=j)
        {
            while(i<high&&nums[i]<=pivot)
                i++;
            while(j>low&&nums[j]>=pivot)
                j--;
            if(i>=j)
                break;
            swap(nums[i], nums[j]);
        }
        swap(nums[low], nums[j]);
        return j;
    }
};

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

注意:

思路同TopK,使用大小为K的小根堆得到前K个频率最大的元素,这里使用哈希表来存储元素与其对应的频率。

尤其注意,在使用仿函数时,一定要把重载()运算符的函数设为public类型,否则其他类调用时,无法访问此类中私有的成员函数。 

class cmp
{
public://注意,一定要把这个操作符重载写成public的,不然默认是private的,运行时在Solution类内无法调用
    bool operator()(const pair<int,int> a,const pair<int,int> b)
    {
        return a.second>b.second;
    }
};
class Solution {
public:
    unordered_map<int,int> m;
    vector<int> topKFrequent(vector<int>& nums, int k) {
        for(int i:nums)//得到数组中的元素与其出现频率的键值对
        {
            m[i]++;
        }
        priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> q;
        for(auto& cond:m) 
        {
            q.push(cond);
            if(q.size()>k)
            {
                q.pop();
            }
        }
        vector<int> ans;
        while(!q.empty())
        {
            auto [x,y]=q.top();
            ans.push_back(x);
            q.pop();
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值