day12休息
day13学习内容:150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素、栈的总结
先把式子转为二叉树,下面的第一个式子为后缀表达式,第二个式子是常用的中序表达式,但缺点是需要加括号,所以计算机内部一般用后缀表达式(后续遍历 顺序是左右中)
遇见数字就加入到栈里,遇到操作符就从栈里取出两个元素进行运算,结束后再放回栈里
class Solution {
public:
int evalRPN(vector& tokens) {
stack sta;
for(int i=0; i
int提交时会溢出,所以改为long
栈非常擅长这种用相邻字符,并进行消除的操作,前面括号匹配也是这样
用队列解决,把队列当作窗口,每移动一次都去掉一个元素,添加一个元素,然后找最大
普通队列不好求最大值
如果使用优先级队列,放到大顶堆里(元素递减)或小顶堆,可能要删除的元素在中间,从而不好删除
所以要使用单调队列,关键在于如何push和pop元素,由自己定义
设计单调队列的时候,pop,和push操作要保持如下规则:
保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。
先跳过本题,思路可以理解,感觉串起来写代码还有些难度
单调队列不是一成不变的,不同场景有不同写法,只是要保证队列里单调递减或递增的原则
主要工作分三部分:1-先统计出频率;2-对频率进行排序;3-取出前k个高频对应的值
可以用map,用Key存值,value存其出现的次数,然后对value进行排序,即使是快排(二分法)时间复杂度也是n*logn
但没有必要都进行排序,可以用大顶堆(根节点比子节点大)和小顶堆(根节点比子节点小)数据结构来解决前k个高频或低频元素
如果用大顶堆,会在pop时把最大元素弹出去了,所以大顶堆是前k个低频元素,所以要用小顶堆,弹出的是堆顶的小元素
堆是二叉树,每次排序是维护k个元素,时间复杂度是n*logk
C++中有现成的优先级队列
值和次数放到map中
定义优先级队列
用优先级队列把map遍历完
把优先级队列中元素倒着放入(频率高的在前面,频率低的在后面)
对于大顶堆定义和遍历map不太熟悉,
顶堆可以等二叉树学完再回头看
class Solution {
public:
vector topKFrequent(vector& nums, int k) {
class mycomparison {
public:
bool operator()(const pair& lhs, const pair& rhs) {
return lhs.second > rhs.second; // 左大于右,小顶堆,右大于左,大顶堆
}
};
// 用map统计元素出现频率
unordered_map map;
for(int i=0; i, vector>, mycomparison> pri_que;
// 用固定大小为k的小顶堆,扫面所有频率的数值
// 主要搞不太懂小顶堆的机制,学完二叉树再返回来看
for(unordered_map::iterator it = map.begin(); it != map.end(); it++){
pri_que.push(*it);
if(pri_que.size() > k){
pri_que.pop();
}
}
// 找出k个高频元素,因为小顶堆先弹出小的值,所以倒叙输出到数组
vector result(k);
for(int i=k-1; i>=0; i--){
result[i] = pri_que.top().first; // 地址的话是->first,但存的是map(*it),则直接.first
pri_que.pop();
}
return result;
}
};
照着写了一遍,基本理解整体思路,主要对大顶堆定义不熟悉,但感觉是背
优先级队列内部元素是自动依照元素的权值排列,在缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以vector为表现形式的complete binary tree(完全二叉树)
堆是一棵完全二叉树
代码随想录
队列的典型应用——单调队列、优先级队列两个比较难,第一遍不太熟悉,没有独立完成代码