[C++][Leetcode][TopK]前K大问题+前K高频(堆+map)

前两天面试的时候,面试官问了前K大的问题:先是找前K大数,其次是前K高频数。按照面试官的思路一道一道展开~

对总体过程中思考的知识点进行一个总结:

  • 为什么快排常用?
    • 在大规模数据的时候,快速排序只会线性增长,而堆排序增加幅度很大,会远远大于线性。
    • 堆排序指针寻址会耗费很多时间,但是快速排序的话只是移动到前后位置。
    • 参考博文为什么快排最好
  • 介绍一下C++构造函数?
    • 构造函数没有返回值
    • 构造函数用作初始化
    • 构造函数可以重载
  • 点操作符和箭头操作符的区别?
    • 点操作符的对象是实体
    • 箭头操作符的对象是指针
  • C++ 优先队列 堆的使用方式?如何自定义?
    • 参考博文自定义堆
  • 为什么sort函数自定义cmp,在类里必须加static关键字?
    • sort中的比较函数compare要声明为静态成员函数或全局函数,不能作为普通成员函数。非静态成员函数是依赖于具体对象的,而std::sort这类函数是全局的,无法再sort中调用非静态成员函数。静态成员函数或者全局函数是不依赖于具体对象的, 可以独立访问,无须创建任何对象实例就可以访问。同时静态成员函数不可以调用类的非静态成员。参考博文

 

目录

1.  Leetcode 215. 数组中的第K个最大元素

2. Leetcode 703. 数据流中的第K大元素

3. Leetcode 面试题 17.14. 最小K个数

4. Leetcode 347. 前 K 个高频元素

 


1.  Leetcode 215. 数组中的第K个最大元素

  • 题目描述

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 思路分析

这个问题有一种非常常见的思路,就是排序,然后取第K个元素即可。最好的时间复杂度是nlogn。但是这个思路,显然不能让面试官满意。说到排序,我们常用的就是快速排序。排序排序有一个partion函数,设定一个哨兵,每次把一个数组分成两部分,前部分小于哨兵元素(或者大于),后部分大于哨兵元素(或者小于)。这样每次调用一次partion函数就可以将一个元素放在其应该在的位置上。我们要求取的是第K大的元素,我们并不关心前k-1个元素是否有序。所以我们可以采用partion函数来寻找第K大的元素。按照通常的解法,我们选取第一个元素作为哨兵。经过一轮partion,如果当前元素的下标小于k-1,表示我们要找的第K大的元素在当前元素的后半部分,否则反之。这样我们最多调用K次partion就可以找到第K大的元素,时间复杂度为Klogn.

  • 代码设计
class Solution {
public:
    void partion(vector&nums,int left,int right,int k)
    {
        if(leftprivot)
                {
                     ++i;
                }
                if(ik-1)
                partion(nums,left,i-1,k);
            else
                return;
    
        }
    }
    int findKthLargest(vector& nums, int k) {
        int n=nums.size();
        if(n<=0||n

这时候,面试官接着问,如果是数据流呢?你事先并不知道有多少个元素?这时候,我们只知道要求前K大。

2. Leetcode 703. 数据流中的第K大元素

  • 题目描述

设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。

你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。

示例:

int k = 3;
int[] arr = [4,5,8,2];
KthLargest kthLargest = new KthLargest(3, arr);
kthLargest.add(3);   // returns 4
kthLargest.add(5);   // returns 5
kthLargest.add(10);  // returns 5
kthLargest.add(9);   // returns 8
kthLargest.add(4);   // returns 8
说明:
你可以假设 nums 的长度≥ k-1 且k ≥ 1。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-a-stream
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  •  思路分析

既然不知道有多少数,我们就想到了堆。我们只需要维护一个大小为K的最小堆,那么堆定元素就是第K大的元素。最小堆的堆顶元素小于堆里的其他元素。使用STL的优先队列构建堆。

  • 代码设计
class KthLargest {
public:

    priority_queue< int ,vector< int >,greater< int > >maxheap;
    int K;
    KthLargest(int k, vector& nums) {
           int n=nums.size();
           K=k;
           if(nadd(val);
 */

3. Leetcode 面试题 17.14. 最小K个数

  • 题目描述

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]
提示:

0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-k-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 代码设计
class Solution {
public:
    void partion(vector&nums,int left,int right,int k)
    {
        if(left=privot)
                    --j;
                
                if(i < j)
                {
                    nums[i++]=nums[j];
                }
                
                while(i < j&&nums[i]k-1)
                partion(nums,left,i-1,k);
            else
                return;
        }
    }
    vector smallestK(vector& arr, int k) {
        int n=arr.size();
        vectorres;
        if(n<=0||n

这时候,面试官说,我们再来看一道题吧,说返回前k高频个高频出现的元素。

4. Leetcode 347. 前 K 个高频元素

  • 题目描述

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

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

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

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/top-k-frequent-elements
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

  • 思路分析
    • 第一种思路:使用map存储元素以及其出现的频数。创建一个vector存储map里的元素对。根据第二个元素的大小进行进行降序排序,然后返回前K个元素即可。
    • 第二种思路:使用map存储元素以及其出现的频数。维护一个最小堆,大小为K,存储的元素为map里的元素对。然后返回这个最小堆里的元素即可。
  • 代码设计
class Solution {
public:

    struct cmp {
	   bool operator()(const pair&a,const pair&b)
       {
            return a.second>b.second;
       }
		   
    };
    vector topKFrequent(vector& nums, int k) {
        mapm;
        vectorres;
        priority_queue,vector>,cmp >q;
        for(int i=0;i ::iterator it;
       for(it=m.begin();it!=m.end();++it)
       {
           if(q.size()first,it->second));
            else
            {
    
                if(q.size()==k&q.top().secondsecond)
                {
                    q.pop();
                    q.push(make_pair(it->first,it->second));
                }
            }
       }

       while(!q.empty())
       {
           res.push_back(q.top().first);
           q.pop();
       }

        return res;
        


    }
};
class Solution {
public:
    static bool cmp(const pair&a,const pair&b)
    {
        return a.second > b.second;
    }
    vector topKFrequent(vector& nums, int k) {
        mapm;
        vectorres;
       
        for(int i=0;i>v;
        map::iterator it;
        for(it=m.begin();it!=m.end();++it)
        {
            v.push_back(make_pair(it->first,it->second));
        }

        sort(v.begin(),v.end(),cmp);

        if(k>v.size())
            k=v.size();
        cout<

 

你可能感兴趣的:(面试系列,C++程序设计,Leetcode)