我在代码随想录|写代码Day14之栈和队列-150. 逆波兰表达式求值,239. 滑动窗口最大值,347. 前 K 个高频元素
学习目标:
博主介绍: 27dCnc
专题 : 数据结构帮助小白快速入门
👍👍👍👍👍👍👍👍👍👍👍👍
☆*: .。. o(≧▽≦)o .。.:*☆
主题: 栈
今日份打卡
- 代码随想录-栈
学习内容:
- 逆波兰表达式求值
- 滑动窗口最大值
- 前 K 个高频元素
- 栈与队列总结
150. 逆波兰表达式求值
经典题目
图解
栈与递归之间在某种程度上是可以转换的,其实逆波兰表达式相当于是二叉树中的后序遍历。
- 遇到数字进栈
- 遇到运算符进行加减运算
- 将运算结果放入栈中
- 直到将字符串最后一个元素遍历后栈中仅剩一个元素后返回答案
代码
class Solution {
public:
int evalRPN(vector<string>& s) {
stack<int>st;
for(int i=0;i < s.size();i++) {
if(st.empty() || (s[i].compare("+") && s[i].compare("-") && s[i].compare("*") && s[i].compare("/"))) {
int num = atoi(s[i].c_str());
st.push(num);
} else {
int x = st.top();
st.pop();
int y = st.top();
st.pop();
switch(s[i][0]) {
case '+' : st.push(x+y);break;
case '-' : st.push(y-x);break;
case '*' : st.push(x*y);break;
case '/' : st.push(y/x); break;
}
}
}
return st.top();
}
};
错误汇总:
不能如下:
if(st.empty() || (s[i] != ‘+’ && s[i] != ‘-’ && s[i] != ‘*’ && s[i] != ‘/’)) {
int num = atio(&s[i]);
也不可以如下:
if(st.empty() || (s[i].compare(‘+’) && s[i].compare(‘-’) && s[i].compare(‘*’) && s[i].compare(‘/’))) {
int num = atio(&s[i]);
正确如下:
if(st.empty() || (s[i].compare(“+”) && s[i].compare(“-”) && s[i].compare(“*”) && s[i].compare(“/”))) {
int num = atoi(s[i].c_str());
原因: compare
比较的是字符串 ''这样代表字符
atoi()
转化的是字符串而且是c语言风格所以要用 .c_str()
格式化
还有为什么要 s[i][0]
我也不太清楚
其他语言版本
Python
from operator import add, sub, mul
class Solution:
op_map = {'+': add, '-': sub, '*': mul, '/': lambda x, y: int(x / y)}
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for token in tokens:
if token not in {'+', '-', '*', '/'}:
stack.append(int(token))
else:
op2 = stack.pop()
op1 = stack.pop()
stack.append(self.op_map[token](op1, op2)) # 第一个出来的在运算符后面
return stack.pop()
Java
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for (String s : tokens) {
if ("+".equals(s)) { // leetcode 内置jdk的问题,不能使用==判断字符串是否相等
stack.push(stack.pop() + stack.pop()); // 注意 - 和/ 需要特殊处理
} else if ("-".equals(s)) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(s)) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
GO
func evalRPN(tokens []string) int {
stack := []int{}
for _, token := range tokens {
val, err := strconv.Atoi(token)
if err == nil {
stack = append(stack, val)
} else { // 如果err不为nil说明不是数字
num1, num2 := stack[len(stack)-2], stack[(len(stack))-1]
stack = stack[:len(stack)-2]
switch token {
case "+":
stack = append(stack, num1+num2)
case "-":
stack = append(stack, num1-num2)
case "*":
stack = append(stack, num1*num2)
case "/":
stack = append(stack, num1/num2)
}
}
}
return stack[0]
}
239. 滑动窗口最大值
题目
代码
class MyQueue {
public:
deque<int> que;//使用deque来实现单调队列
//每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出
//同时pop之前判断队列是否为空
void pop(int value) {
if(!que.empty() && value == que.front()) {
que.pop_front();
}
}
//如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出
void push(int value) {
while(!que.empty() && value > que.back()) {
que.pop_back();
}
que.push_back(value);
}
//查询当前队列里的最大值,直接返回队列前端也就是front就可以了
int front() {
return que.front();
}
};
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> ans;
for(int i = 0;i < k;i++) {
que.push(nums[i]);
}
ans.push_back(que.front());//ans记录前K个元素最大值
for(int i = k ;i < nums.size();i++) {
que.pop(nums[i - k]);
que.push(nums[i]);
ans.push_back(que.front());
}
return ans;
}
};
图解
347. 前 K 个高频元素
题目
代码
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; //map<nums[i],对应出现次数
for(int i = 0;i < nums.size();i++) {
map[nums[i]]++;
}
//对频率排序
//定义一个小顶堆,大小为k
priority_queue<pair<int,int>,vector<pair<int,int>>,mycomparison> pri_que;
//用于固定大小为k的小顶堆,扫面所以频率数值
for(unordered_map<int,int>::iterator it = map.begin();it != map.end();it++) {
pri_que.push(*it);
if (pri_que.size() > k) {
pri_que.pop();
}
}
vector<int> result(k);
for(int i=k-1;i>=0;i--) {
result[i] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};
栈和队列总结
灵魂四问
- C++中stack,queue 是容器么?
- 我们使用的stack,queue是属于那个版本的STL?
- 我们使用的STL中stack,queue是如何实现的?
- stack,queue 提供迭代器来遍历空间么?
陷阱1:栈是容器适配器,底层容器使用不同的容器,导致栈内数据在内存中不一定是连续分布的。
陷阱2:缺省情况下,默认底层容器是deque,那么deque在内存中的数据分布是什么样的呢? 答案是:不连续的,下文也会提到deque。
栈经典题目
- 栈在系统中的应用
- 括号匹配问题
- 字符串去重问题
- 逆波兰表达式问题
队列的经典题目
- 滑动窗口最大值问题
- 求前 K 个高频元素
学习时间:
- 周一至周五晚上 7 点—晚上9点
- 周六上午 9 点-上午 11 点
- 周日下午 3 点-下午 6 点
学习产出:
- 技术笔记 2 遍
- CSDN 技术博客 3 篇
- 习的 vlog 视频 1 个
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~
本文作者:2c237c6
本文链接:https://www.cnblogs.com/27dCnc/p/18568656
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步