代码随想录算法训练营第10天|150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素
LeetCode150
2025-01-31 21:05:49 星期五
题目描述:力扣150
文档讲解:代码随想录(programmercarl)150. 逆波兰表达式求值
视频讲解:《代码随想录》算法视频公开课:栈的最后表演! | LeetCode:150. 逆波兰表达式求值
代码随想录视频内容简记
梳理
-
一个for循环遍历字符串
s
-
之后分别用
if-else
判断遍历的时数字还是计算符。如果是计算符,则弹出两个栈顶的元素进行计算之后(注意题目中说明了逆波兰表达式是合法的,所以不用担心对空栈进行操作),再压入栈中;如果是数字,则直接压入栈中 -
最后遍历结束,返回栈顶元素,释放内存即可
大致代码内容
-
在if判断然后向栈中压入元素时,需要注意num1和num2的顺序
if (tokens[i] == "/") st.push(num2 / num1);
,举个例子,["4","13","5","/","+"]
,写成num1
和num2
的顺序写反了就是完全两个不一样的结果。这个千万要注意 -
定义了一个整型的数组,所以需要对其中的元素进行类型转换,可以使用C++标准库中的
stoi()
函数,转换为整型,还有一个stoll()
函数可以转换为long long
型。st.push(stoi(tokens[i]))
LeetCode测试
左闭右闭
点击查看代码
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for (int i = 0; i < tokens.size(); i++) {
// JiaoJiao
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
int num1 = st.top(); st.pop();
int num2 = st.top(); st.pop();
if (tokens[i] == "+") st.push(num2 + num1);
if (tokens[i] == "-") st.push(num2 - num1);
if (tokens[i] == "*") st.push(num2 * num1);
if (tokens[i] == "/") st.push(num2 / num1);
} else {
st.push(stoi(tokens[i]));
}
}
int result = st.top();
st.pop();
return result;
}
};
LeetCode239
题目描述:力扣239
文档讲解:代码随想录(programmercarl)239. 滑动窗口最大值
视频讲解:《代码随想录》算法视频公开课:单调队列正式登场!| LeetCode:239. 滑动窗口最大值
代码随想录视频内容简记
题目设计就是要实现一个单调队列,来维护队列内的元素,目的就是要实现队列的单调递减或者单调递增。在本题中,我们就是要实现一个单调递减的队列,核心和难点就是如何设计对应的判断来维持这个单调递减的队列
梳理
注意要时刻维护单调队列出口处的元素为最大值
-
使用一个
push()
函数用于压入队列入口处(右边)的元素。将滑动窗口新增的元素记为k,其规则是如果在push
的时候,单调队列前面所有小于该元素k的队列元素都需要被弹出。如果该元素k小于前面的队列元素数组,那么可以压入队列 -
使用一个
pop()
函数负责弹出队列出口处(左边)的元素。因为队列维护的就是一个最大值,所以每次在队列中需要pop()
的元素都是滑动窗口的最大值。将滑动窗口移除的元素记为k,那么如果单调队列的出口元素和k相等,则可以弹出单调队列中的元素。 -
使用一个
get_max_value()
函数计算滑动窗口内的最大值,每次将单调队列的队头元素(出口是front,入口是back)进行弹出即可
大致代码内容
-
关于
pop()
函数,if (!queue.empty() && value == queue.front()) queue.pop_front()
-
关于
push()
函数,if (!queue.empty() && value > queue.back()) queue.pop_back()
-
关于
get_max_value()
函数,直接return queue.front()
LeetCode测试
这个题太复杂了,😵😵,第一次接触这个做法
点击查看代码
class Solution {
private:
class MyQueue {
public:
deque<int> que;
void pop(int value) {
if (!que.empty() && que.front() == value) que.pop_front();
}
void push(int value) {
while (!que.empty() && value > que.back()) que.pop_back();
que.push_back(value);
}
int get_max_value() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
for (int i = 0; i < k; i++) {
que.push(nums[i]);
}
result.push_back(que.get_max_value());
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]);
que.push(nums[i]);
result.push_back(que.get_max_value());
}
return result;
}
};
LeetCode347
题目描述:力扣347
文档讲解:代码随想录(programmercarl)347.前 K 个高频元素
视频讲解:《代码随想录》算法视频公开课:优先级队列正式登场!大顶堆、小顶堆该怎么用?| LeetCode:347.前 K 个高频元素
代码随想录视频内容简记
首先是大顶堆和小顶堆,大顶堆每次pop()
的元素是堆顶最大的元素,而小顶堆每次弹出的是堆顶最小的元素;本体要保留前K个高频元素,也就是前K个最大的元素,那么需要用到小顶堆,把每次的最小值弹出去
优先级队列,实现优先级队列的数据结构就是堆
梳理
-
首先用
map
这种数据结构来存储数组每个元素(key)和对应的频率(value) -
之后定义一个小顶堆,需要手写一个比较函数,k哥说直接看网站上的写。然后对
map
进行遍历,在优先级队列中进行储存,如果队列的长度大于K,那么就进行弹出 -
因为最后的优先级队列进行输出,会得到一个从小到大的排列,所以还需要定义一个数组result,遍历优先级队列,将最后的结果反向添加到result中
-
最后返回result
大致代码内容
-
for (map : it)
,这里的意思是:将map的每一个元素映射到it上进行遍历,if (que.size > k) que.pop()
-
for (int i = k - 1; i > 0; i--)
,注意这里的初始条件是是k - 1
,result[i] = que.top().first
这里对result进行反向添加。这里注意不能写成result.push_back(que.top().first);
因为这行代码的本质还是按数组的索引顺序依次往后面添加
LeetCode测试
代码中关于小根堆的实现,创建优先级队列还有优先级队列的映射操作比较陌生,代码里还是有一些细节需要注意,比如在这里定义vector需要写清楚数组大小为k,que.top().first
的first后面没有括号这样等等
感觉这个题也不好写
点击查看代码
class Solution {
public:
class mycomparison {
public:
// 实现小顶堆
bool operator() (const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) map[nums[i]]++;
// 创建一个优先级队列,对value进行排序
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> que;
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
que.push(*it);
if (que.size() > k) {
que.pop();
}
}
vector<int> result(k);
for (int i = k - 1; i >= 0; i--) {
result[i] = que.top().first;
que.pop();
}
return result;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!