239 滑动窗口最大值
题目链接:
239. 滑动窗口最大值 - 力扣(LeetCode)
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
思路:
使用单调递减队列,队列大小为k,队首即为答案。前k个直接push到队列中,之后每次pop掉它前面k个的元素,而由于入队保持了递减,因此队列未必真的有该元素,因此只有队首元素与需要pop的相等时,才真正pop。
class Solution {
public:
deque<int> Q;
void push(int val)
{
while(!Q.empty() && Q.back() < val)
{
Q.pop_back();
}
Q.push_back(val);
}
void pop(int val)
{
if(!Q.empty() && Q.front() == val)
{
Q.pop_front();
}
}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ans;
int len = nums.size();
for(int i = 0; i < len; i++)
{
push(nums[i]);
if (i < k - 1) continue;
ans.push_back(Q.front());
pop(nums[i - k + 1]);
}
return ans;
}
};
347 前K个高频元素
题目链接:
347. 前 K 个高频元素 - 力扣(LeetCode)
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
方法一 大根堆
C++中priority_queue默认为大顶堆。
首先统计各个数的频率,将统计信息全部插入到大顶堆中,要根据频率排序,因此应该先插入频率,后插入元素。
后面再取出前k个元素,即为答案。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> H;
vector<int> ans;
for(auto num : nums)
{
H[num]++;
}
priority_queue<pair<int, int>> Q;
for(auto p : H)
{
Q.push({p.second, p.first});
}
for(int i = 0; i < k; i++)
{
ans.push_back(Q.top().second);
Q.pop();
}
return ans;
}
};
时间复杂度:O(nlogn)
n为map中的元素个数
方法二 小根堆
使用小根堆,可进一步降低复杂度。首先统计各个数的频率,将k个统计信息插入到小根堆中,当超过k个时,则弹出元素,由于是小根堆,此时弹出的必为最小的,因此,最终小根堆中的所有元素即为答案。
注意:本方法向priority_queue传入cmp时,要么写在一个class/struct里面,要么写成lambda表达式。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> H;
vector<int> ans;
for(auto num : nums)
{
H[num]++;
}
auto cmp = [&](const pair<int, int>& a, const pair<int, int>& b)
{
return a.second > b.second;
};
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(cmp)> Q(cmp);
for(auto p : H)
{
Q.push({p.first, p.second});
while(Q.size() > k)
{
Q.pop();
}
}
while(!Q.empty())
{
ans.push_back(Q.top().first);
Q.pop();
}
return ans;
}
};
时间复杂度:O(nlogk),n为map中元素个数
方法三 桶排序
首先统计各个数的频率,创建一个桶,将频率作为下标,桶中为对应频率的元素的数。从高频的桶开始找元素,直到找到k个元素。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> counts;
for(auto num : nums)
{
counts[num]++;
}
vector<int> res;
vector<vector<int>> bucket(nums.size() + 1);;
for (auto it : counts)
{
int freq = it.second;
int num = it.first;
bucket[freq].push_back(num);
}
for (int i = bucket.size() - 1; i >= 0 && res.size() < k; i--)
{
for (int num : bucket[i])
{
res.push_back(num);
if (res.size() == k) {
break;
}
}
}
return res;
}
};
时间复杂度:O(N),N为nums中元素个数
参考题解:
https://leetcode.cn/problems/top-k-frequent-elements/solutions/11201/leetcode-di-347-hao-wen-ti-qian-k-ge-gao-pin-yuan-