当前位置: 首页 > web >正文

C++算法训练营 Day11 栈与队列(2)

1.逆波兰表达式求值

给你一个字符串数组tokens,表示一个根据逆波兰表示法表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

有效的算符为 '+''-''*' '/'
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用32 位整数表示。

示例 1:

输入:tokens = [“2”,“1”,“+”,“3”,“*”]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) *3) = 9

示例 2:

输入:tokens = [“4”,“13”,“5”,“/”,“+”]
输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13/ 5)) = 6

示例 3:

输入:tokens = [“10”,“6”,“9”,“3”,“+”,“-11”,““,”/“,””,“17”,“+”,“5”,“+”]
输出:22
解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

  • 解题思路:

逆波兰表达式即后缀表达式,其特点为:
1.运算符在操作数之后
2.无需括号即可明确运算顺序
3.适合栈结构计算

(1)创建存储操作数的栈。

// 使用 long long 类型栈防止溢出stack<long long> st;

(2)然后遍历 token所有值,若遇到操作数,就进行压栈处理;若遇到运算符,就进行弹出栈中所有操作数,然后进行运算,这里要注意:先弹出的操作数是后一项,即被减数或被除数

 // 遍历所有 tokenfor (int i = 0; i < tokens.size(); i++) {// 当前 token 是运算符if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {// 弹出栈顶两个操作数(注意顺序)long long num1 = st.top();  // 右操作数(后进栈)st.pop();long long num2 = st.top();  // 左操作数(先进栈)st.pop();// 根据运算符执行相应计算if (tokens[i] == "+") st.push(num2 + num1);   // 加法else if (tokens[i] == "-") st.push(num2 - num1);   // 减法(注意操作数顺序)else if (tokens[i] == "*") st.push(num2 * num1);   // 乘法else if (tokens[i] == "/") st.push(num2 / num1);   // 除法(注意操作数顺序)}// 当前 token 是操作数else {// 将字符串转换为 long long 并压栈st.push(stoll(tokens[i]));  // stoll = string to long long}}

(3)遍历完成后,获取栈中操作数的值,对于栈中操作数弹不弹出都没影响。

// 获取最终结果long long result = st.top();st.pop();  // 清空栈(可选操作)return result;  // 返回整型结果

完整代码如下:

class Solution {
public:int evalRPN(vector<string>& tokens) {// 使用 long long 类型栈防止溢出stack<long long> st;// 遍历所有 tokenfor (int i = 0; i < tokens.size(); i++) {// 当前 token 是运算符if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {// 弹出栈顶两个操作数(注意顺序)long long num1 = st.top();  // 右操作数(后进栈)st.pop();long long num2 = st.top();  // 左操作数(先进栈)st.pop();// 根据运算符执行相应计算if (tokens[i] == "+") st.push(num2 + num1);   // 加法else if (tokens[i] == "-") st.push(num2 - num1);   // 减法(注意操作数顺序)else if (tokens[i] == "*") st.push(num2 * num1);   // 乘法else if (tokens[i] == "/") st.push(num2 / num1);   // 除法(注意操作数顺序)}// 当前 token 是操作数else {// 将字符串转换为 long long 并压栈st.push(stoll(tokens[i]));  // stoll = string to long long}}// 获取最终结果long long result = st.top();st.pop();  // 清空栈(可选操作)return result;  // 返回整型结果}
};

2.滑动窗口最大值

给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
在这里插入图片描述

示例 2:

输入:nums = [1], k = 1
输出:[1]

  • 解题思路

本题利用到单调队列,所谓单调队列就是:维护一个元素值单调递减的双端队列(队头到队尾递减),队头元素始终是当前窗口的最大值,从而高效获取滑动窗口的最大值,避免每次遍历窗口。

(1)先初始化,创建单调队列
(2)填充初始窗口:将前k个元素加入队列,并记录初始最大值,即获取队列头部元素。
(3)滑动窗口:先移除窗口左侧元素(如果它仍是当前最大值),然后添加窗口右侧新元素(维护队列单调性),最后获取当前窗口最大值。
(4)返回结果。

class Solution {
private:// 自定义单调队列类class MyQueue {public:deque<int> que; // 双端队列作为底层存储// 移除元素(仅在元素等于队首时移除)void pop(int value) {// 只有当队列非空且队首等于要移除的值时才弹出if (!que.empty() && value == que.front()) {que.pop_front();}}// 添加元素(维护单调递减特性)void push(int value) {// 移除比当前值小的所有尾部元素while (!que.empty() && value > que.back()) {que.pop_back(); // 这些小的值不可能成为后面窗口的最大值}// 添加当前值到队尾que.push_back(value);}// 获取当前队列中的最大值(即队首元素)int front() {return que.front();}};public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {MyQueue que; // 创建单调队列实例vector<int> result; // 存储结果的向量// 填充初始窗口(前k个元素)for (int i = 0; i < k; i++) {que.push(nums[i]); // 添加元素并维护单调性}result.push_back(que.front()); // 记录初始窗口的最大值// 滑动窗口并处理后续元素for (int i = k; i < nums.size(); i++) {// 移除窗口左侧元素(如果它仍是当前最大值)que.pop(nums[i - k]); // 移除离开窗口的元素// 添加窗口右侧新元素que.push(nums[i]); // 添加新进入窗口的元素// 记录当前窗口的最大值result.push_back(que.front());}return result;}
};

3.前 K 个高频元素

给你一个整数数组nums和一个整数k,请你返回其中出现频率前k高的元素。你可以按任意顺序返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

  • 解题思路:

执行过程示例
假设输入:nums = [1,1,1,2,2,3], k = 2

步骤1:统计频率
元素: 1 → 频率: 3
元素: 2 → 频率: 2
元素: 3 → 频率: 1

步骤2:构建小顶堆(维护K=2)
添加 [1:3] → 堆: [1:3]
添加 [2:2] → 堆: [2:2] [1:3](堆顶是2:2)
添加 [3:1] → 堆: [3:1] [1:3] [2:2] → 堆大小>2 → 弹出堆顶(3:1)
最终堆: [2:2] [1:3](堆顶是2:2)

步骤3:提取结果
倒序输出:
i=1: 堆顶2 → 结果[1]=2
i=0: 堆顶1 → 结果[0]=1
最终结果: [1,2]

class Solution {
public://自定义比较器类(小顶堆)class mycomparison {public://重载 () 运算符,用于比较两个 pairbool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {//比较频率值:lhs.second > rhs.second 返回 true//这样在优先队列中,频率较小的元素会被放在堆顶return lhs.second > rhs.second;}};vector<int> topKFrequent(vector<int>& nums, int k) {// 1.统计元素出现频率unordered_map<int, int> map; //存储<元素, 出现次数>for (int i = 0; i < nums.size(); i++) {map[nums[i]]++; //统计每个元素的出现次数}// 2.创建小顶堆存储 Top K 元素//参数说明://- pair<int, int>: 存储<元素, 频率>//- vector<pair<int, int>>: 底层容器//- mycomparison: 自定义比较器priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;//3.遍历频率表,维护大小为 K 的小顶堆for (auto it = map.begin(); it != map.end(); it++) {pri_que.push(*it); //将当前元素加入堆//堆大小超过 K 时,移除频率最小的元素if (pri_que.size() > k) {pri_que.pop(); //弹出堆顶(当前最小频率元素)}}//4.提取结果(倒序输出)vector<int> result(k);for (int i = k - 1; i >= 0; i--) {result[i] = pri_que.top().first; //获取元素值pri_que.pop(); //移除已处理元素}return result;}
};
http://www.xdnf.cn/news/12630.html

相关文章:

  • mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
  • 阿里云ACP云计算备考笔记 (4)——企业应用服务
  • 【MySQL】视图、用户管理、MySQL使用C\C++连接
  • 【数据结构初阶】单链表
  • Harmony核心:动态方法修补与.NET游戏Mod开发
  • Java实现飞机射击游戏:从设计到完整源代码
  • 【小红书拥抱开源】小红书开源大规模混合专家模型——dots.llm1
  • 使用WPF的Microsoft.Xaml.Behaviors.Wpf中通用 UI 元素事件
  • 从代码学习深度强化学习 - 初探强化学习 PyTorch版
  • 怎么解决cesium加载模型太黑,程序崩溃,不显示,位置不对模型太大,Cesium加载gltf/glb模型后变暗
  • 开心农场日记之~ 一颗向日葵的成长记录~
  • 基恩士X520 MC通信寄存器转换
  • 如何在软件著作权补正时查看已提交的程序鉴别材料和文档鉴别材料
  • 项目课题——功耗蓝牙(BLE)室内定位系统
  • python queue
  • Python|GIF 解析与构建(5):手搓截屏和帧率控制
  • 摆脱硬件依赖:SkyEye在轨道交通中的仿真应用
  • Python训练day40
  • 33 C 语言字符串转数值函数详解:atoi、atol、atoll、atof
  • D3.js与vue3力导向图开发全流程
  • 【机械视觉】Halcon—【八、形态学调整和生成棋盘格】
  • AI智能编码工具:阿里通义灵码使用个人版
  • 拆钢琴清理,装导电橡胶从电路板背后装好装
  • MySQL 索引优化(Explain执行计划) 详细讲解
  • 8天Python从入门到精通【itheima】-73~74(数据容器“集合”+案例练习)
  • 《前端面试题:JavaScript 变量》
  • 关于DSP数据类型长度的思考
  • openlayers实现可拖拽的节点(类似知识图谱)
  • 地震勘探——地震波速度、地震子波、合成地震记录、影响地震振幅的因素
  • 巨控GRM550系列,西门子 S7-1200 PLC 远程上下载与调试技术方案