前两天面试的时候,面试官问了前K大的问题:先是找前K大数,其次是前K高频数。按照面试官的思路一道一道展开~
对总体过程中思考的知识点进行一个总结:
目录
1. Leetcode 215. 数组中的第K个最大元素
2. Leetcode 703. 数据流中的第K大元素
3. Leetcode 面试题 17.14. 最小K个数
4. Leetcode 347. 前 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大。
题目描述
设计一个找到数据流中第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);
*/
设计一个算法,找出数组中最小的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高频个高频出现的元素。
给定一个非空的整数数组,返回其中出现频率前 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
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<