代码随想录算法训练营
Day11 代码随想录算法训练营第 11 天 | LeetCode150. 逆波兰表达式求值 LeetCode239. 滑动窗口最大值 LeetCode347.前 K 个高频元素
目录
前言
LeetCode150. 逆波兰表达式求值
LeetCode239. 滑动窗口最大值
LeetCode347.前 K 个高频元素
一、LeetCode150. 逆波兰表达式求值
1.题目链接
2.思路
(1)遍历字符串数组
(2)如果遇到数字,则放入栈中
(3)遇到符号,则弹出栈顶前两个元素,运算后压回栈中
(4)返回栈顶元素
细节:数组元素为字符串
1)判定是,以±*/作为判断条件更容易
2)将数字压入栈中时,用stoll()函数将字符串转换成long long类型
3)数据范围使得我们需要long long
3.题解
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> st;
int n = tokens.size();
for (int i = 0; i < n; i++) {
if (tokens[i] == "+") {
long long temp = st.top();
st.pop();
long long num = st.top();
st.pop();
st.push(num + temp);
} else if (tokens[i] == "-") {
long long temp = st.top();
st.pop();
long long num = st.top();
st.pop();
st.push(num - temp);
} else if (tokens[i] == "*") {
long long temp = st.top();
st.pop();
long long num = st.top();
st.pop();
st.push(num * temp);
} else if (tokens[i] == "/") {
long long temp = st.top();
st.pop();
long long num = st.top();
st.pop();
st.push(num / temp);
} else {
st.push(stoll(tokens[i]));
}
}
return st.top();
}
};
二、LeetCode239. 滑动窗口最大值
1.题目链接
2.思路
(1)难点:获取最大值
(2)不能用优先级队列,因为优先级队列会改变左右端点在队列中的位置
(3)实现单调队列表示滑动窗口
1)主体思路
三个方法pop、push、get_max
先建立第一个滑动窗口,将元素push进入队列
此后pop左端元素,push右端元素,get_max获取答案
2)方法实现
push:每个元素x在加入队列时,弹出它前面所有小于它的元素,最后将x加入队尾,使得每个元素前面都没有比自己小的元素,队首元素为滑动窗口最大值
pop:若要弹出x,则只有x为队首元素时需要弹出。弹出的是最左端元素,是最先入队的,如果x不是队首元素,那么它在最大值入队的时候一定被弹出
get_max:返回队首
3.题解
class myqueque {
public:
deque<int> q;
void pop(int x) {
if (!q.empty() && x == q.front())
q.pop_front();
}
void push(int x) {
while (!q.empty() && x > q.back())
q.pop_back();
q.push_back(x);
}
int get_max() { return q.front(); }
};
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
myqueque q;
int n = nums.size();
vector<int> ans;
for (int i = 0; i < k; i++) {
q.push(nums[i]);
}
ans.push_back(q.get_max());
for (int i = k; i <= n - 1; i++) {
q.pop(nums[i - k]);
q.push(nums[i]);
ans.push_back(q.get_max());
}
return ans;
}
};
五、LeetCode347.前 K 个高频元素
1.题目链接
2.思路
大顶堆和小顶堆适合解决前k个高频元素/低频元素
(1)为什么选择小顶堆:
在堆的元素多于k个时,需要弹出元素,而优先从根节点弹出元素,若用大顶堆则会丢失最大值
(2)小顶堆和大顶堆的数据结构:优先队列priority_queue
(3)过程:
三个任务:求频率、排序、取前K个
1)先遍历数组,将元素和频率放进map,元素为key,频率为value,便于同时保存元素和频率
2)遍历映射,将映射压入优先队列,再判断优先队列大小,如果优先队列大小超过k,则pop
3)最后将优先队列中每个映射的value赋给数组
(4)本题一些易错的语法
1)priority_queue定义
2)重载运算符
3)map迭代器的使用
3.题解
class Solution {
public:
class compare
{
public :
bool operator()(pair<int,int>& p1,pair<int,int>& p2)
{
return p1.second>p2.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
int n=nums.size();
unordered_map <int,int>m;
for(int i=0;i<n;i++)
{
m[nums[i]]++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,compare> q;
for(unordered_map<int,int>::iterator it=m.begin();it!=m.end();it++)
{
q.push(*it);
if(q.size()>k)q.pop();
}
vector<int> res;
for(int i=k-1;i>=0;i--)
{
res.push_back(q.top().first);
q.pop();
}
return res;
}
};
总结
本章重点
1、用队列实现栈
2、用站实现队列
3、栈的应用:逆波兰式、有效括号
4、队列应用:滑动窗口最大值
5、优先队列:本质是大顶堆和小顶堆,前k个高频元素