一、滑动窗口的最大值
链接:力扣1
描述:
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
思路:自定义一个队列,并且自己定义push和pop的规则。这个队列不用放窗口里的所有元素,只需要放可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。这种队列叫单调队列。
单调队列怎么配合窗口进行滑动呢?
设计单调队列的时候,pop,和push操作要保持如下规则:
- pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止。
上述的push操作在排序的同时已经pop掉了不可能成为最大值的元素了,只需调用que.front()就可以返回当前窗口的最大值。
queue在没有指定容器的情况下,deque就是默认底层容器,因此在自定义类使用双端队列来实现上述的规则。
代码如下:
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
class Solution
{
public:
class Myqueue
{
deque<int>q;
public:
void pop(int val)
{
if (!q.empty() && q.front() == val)
{
q.pop_front();
}
}
void push(int val)
{
while (!q.empty() && q.back() < val)
{
q.pop_back();
}
q.push_back(val);
}
int front()
{
return q.front();
}
};
vector<int> maxSlidingWindow(vector<int>& nums, int k)
{
Myqueue q;
vector<int>result;//存放结果
for (int i = 0; i < k; i++)
{
q.push(nums[i]);
}
result.push_back(q.front());
for (int i = k; i < nums.size(); i++)
{
q.pop(nums[i - k]);
q.push(nums[i]);
result.push_back(q.front());
}
return result;
}
};
int main()
{
vector<int>v{ 1,3,-1,-3,5,3,6,7 };
Solution s;
auto ret= s.maxSlidingWindow(v, 3);
return 0;
}
运行如下:
二、前K个高频元素
链接:力扣2
描述:给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
思路:先遍历数组,得到每个元素的频次。再对频率进行排序,可以使用一种 容器适配器就是优先级队列。priority_queue需要用到头文件queue。
优先级队列其实就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。
而且优先级队列内部元素是自动依照元素的权值排列。排序的方法如下:
缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以vector为表现形式的complete binary tree(完全二叉树)。
堆的补充知识:
堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆(堆头是最大元素),小于等于左右孩子就是小顶堆(堆头是最小元素)。
选用大顶堆还是小顶堆?
对于一个大小为k的大顶堆,在每次移动更新大顶堆的时候,每次弹出都把最大的元素弹出去了,无法保留前k个高频元素,而且使用大顶堆就要把所有元素都进行排序。
如果用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
代码实现如下:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;
class Solution
{
public:
class Mycomp
{
public:
bool operator()(pair<int, int>p1, pair<int, int>p2)
{
return p1.second > p2.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k)
{
//统计出现的元素的词频
unordered_map<int, int>m;
for (int i = 0; i < nums.size(); i++)
{
auto mit = m.find(nums[i]);
if (mit != m.end())
{
//找到了相同元素,值加1
(*mit).second++;
}
else
{
m.insert(make_pair(nums[i], 1));
}
}
priority_queue < pair<int, int>, vector<pair<int, int>>,Mycomp>pri_que;
for (unordered_map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
pri_que.push(*it);
if (pri_que.size() > k)
{
pri_que.pop();
}
}
vector<int>result(k);//存放结果,跟result.resize(k);一样
while (k--)
{
result.at(k) = pri_que.top().first;
pri_que.pop();
}
return result;
}
};
int main()
{
Solution s;
vector<int>v{ 1,1,1,2,3,3 };
auto ret=s.topKFrequent(v, 3);
return 0;
}
运行如下: