C++数据结构与算法——栈与队列

C++第二阶段——数据结构和算法,之前学过一点点数据结构,当时是基于Python来学习的,现在基于C++查漏补缺,尤其是树的部分。这一部分计划一个月,主要利用代码随想录来学习,刷题使用力扣网站,不定时更新,欢迎关注!

文章目录

  • 一、用栈实现队列(力扣232)
  • 二、用队列实现栈(力扣225)
  • 三、有效的括号(力扣20)
  • 四、 删除字符串中的所有相邻重复项(力扣1047)
  • 五、逆波兰表达式求值(力扣150)
  • 六、滑动窗口最大值(力扣239)
  • 七、前 K 个高频元素(力扣347)

一、用栈实现队列(力扣232)

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入:
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

class MyQueue {
public:
    MyQueue() {
    }
    // 两个栈配合实现队列
    stack<int> s1;
    stack<int> s2;
    void push(int x) {
        s1.push(x);
        updateS2(s1,s2);
    }
    
    int pop() {
        int result =s2.top();
        s2.pop();
        updateS1(s1,s2);
        return result;
    }
    
    int peek() {
        return s2.top();
    }
    
    bool empty() {
        if(s2.size()==0){
            return true;
        }
        return false;
    }
    // 更新s2
    void updateS2(stack<int> s1,stack<int> &s2){
        // 先将s2清空,再将s1中所有元素添加到s2中
        int s2Size = s2.size();
        for(int i=0;i<s2Size;i++){
            s2.pop();
        }
        // 将s1中所有元素添加到s2中
        int s1Size = s1.size();
        for(int i=0;i<s1Size;i++){
            int temp = s1.top();
            s2.push(temp);
            s1.pop();
        }
    }
    void updateS1(stack<int> &s1,stack<int> s2){
        // 先将s1清空,再将s2中所有元素添加到s1中
        int s1Size = s1.size();
        for(int i=0;i<s1Size;i++){
            s1.pop();
        }
        // 将s1中所有元素添加到s2中
        int s2Size = s2.size();
        for(int i=0;i<s2Size;i++){
            int temp = s2.top();
            s1.push(temp);
            s2.pop();
        }
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

在这里插入图片描述

二、用队列实现栈(力扣225)

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
示例:
输入:
[“MyStack”, “push”, “push”, “top”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

class MyStack {
public:
    MyStack() {

    }
    // 使用一个队列完成
    queue<int> q;
    void push(int x) {
        q.push(x);
    }
    
    int pop() {
        // 将前面的重新添加到队列尾端
        int qSize = q.size()-1;
        for(int i=0;i<qSize;i++){
            q.push(q.front());
            q.pop();
        }
        int result = q.front();
        q.pop();
        return result;
    }
    
    int top() {
        return q.back();
    }
    
    bool empty() {
        if(q.size()==0){
            return true;
        }
        return false;
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

在这里插入图片描述

三、有效的括号(力扣20)

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
提示:
1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成

class Solution {
public:
    bool isValid(string s) {
        if(s.length()%2!=0) return false;
        stack<char> st;
        for(int i=0;i<s.length();i++){
            if(s[i]=='(') st.push(')');
            else if(s[i]=='[') st.push(']');
            else if(s[i]=='{') st.push('}');
            else if(st.empty()||s[i]!=st.top()) return false;
            else st.pop();
        }
        return st.empty();
    }

};

在这里插入图片描述

四、 删除字符串中的所有相邻重复项(力扣1047)

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:“abbaca”
输出:“ca”
解释:
例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
提示:
1 <= S.length <= 20000
S 仅由小写英文字母组成。

class Solution {
public:
    string removeDuplicates(string s) {
        // 使用栈
        stack<char> st;
        for(int i=0;i<s.size();i++){
            if(st.empty()||st.top()!=s[i]){
                st.push(s[i]);
            }
            else{
                st.pop();
            }
        }
        if(st.empty()) return "";
        string result;
        while(!st.empty()){
            result+= st.top();
            st.pop();
        }
        reverse(result.begin(),result.end());
        return result;
    }
};

在这里插入图片描述

五、逆波兰表达式求值(力扣150)

给你一个字符串数组 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

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        //使用栈进行操作
        stack<long long> st;
        long long result;
        for(int i=0;i<tokens.size();i++){
            if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/"){
                // 是符号
                // 取出两个进行运算
                long long num2 = st.top();
                st.pop();
                long long num1 = st.top();
                st.pop();
                if(tokens[i]=="+") st.push(num1+num2);
                else if(tokens[i]=="-") st.push(num1-num2);
                else if(tokens[i]=="*") st.push(num1*num2); 
                else st.push(num1/num2);
            }
            else{
                st.push(stoll(tokens[i]));
            }
        }
        int fin = st.top();
        st.pop();
        return fin;
    }
};

在这里插入图片描述

六、滑动窗口最大值(力扣239)

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length

class Solution {
    // 使用双端队列
    class Myduque{
    public:
        deque<int> dq;
        void mypop(int val){
            if(!dq.empty()&&val==dq.front()){
                dq.pop_front();
            }
        }
        void mypush(int val){
            while(!dq.empty()&&val>dq.back()){
                dq.pop_back();
            }
            // 添加队列
            dq.push_back(val);
        }
        int getMax(){
            return dq.front();
        }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        // 定义结果列表
        vector<int> result;
        Myduque Mydq;
        // 现将前k个元素添加到队列
        for(int i=0;i<k;i++){
            Mydq.mypush(nums[i]);
        }
        // 添加结果
        result.push_back(Mydq.getMax());
        for(int i=k;i<nums.size();i++){
            // 添加一个
            Mydq.mypush(nums[i]);
            // 弹出一个
            Mydq.mypop(nums[i-k]);
            // 结果添加到列表
            result.push_back(Mydq.getMax());
        }
        return result;
    }
};

在这里插入图片描述

七、前 K 个高频元素(力扣347)

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105
k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

class Solution {
    class Mycompare{
    public:
        bool operator()(const pair<int,int> &left,const pair<int,int> &right){
            return left.second>right.second;
        }
    };
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        // 结果数组
        vector<int> result;
        // 使用map存储
        unordered_map<int,int> Mymap;
        // 统计每个元素出现的次数
        for(int i=0;i<nums.size();i++){
            Mymap[nums[i]]++;
        }
        // for(unordered_map<int,int>::iterator it=Mymap.begin();it!=Mymap.end();it++){
        //     cout<<(*it).first<<":"<<(*it).second<<endl;
        // }
        // 使用小顶堆筛选出出现次数最多的k个
        priority_queue<pair<int,int>,vector<pair<int,int>>,Mycompare> smallQueue;
        // 遍历map,添加到优先队列中
        for(unordered_map<int,int>::iterator it=Mymap.begin();it!=Mymap.end();it++){
            smallQueue.push(*it);
            if(smallQueue.size()>k){
                smallQueue.pop();
            }
        }
        // 获取最终的结果
        while(!smallQueue.empty()){
            result.push_back(smallQueue.top().first);
            smallQueue.pop();
        }
        return result;
    }
};

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/391082.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java+SSM+mysql 开放式实验管理系统78512-计算机毕业设计项目选题推荐(免费领源码)

摘 要 我国高校开放式实验管理普遍存在实验设备使用率较低、管理制度不完善,实验设备共享程度不高等诸多问题。要在更大范围推行开放式实验管理,就必须在开放式实验教学管理流程中,通过引入信息化管理加大信息技术在其中的应用,才能真正发挥这种教学模式的开放性优势。 本系统…

C#,二进制数的非0位数统计(Bits Count)的算法与源代码

计算一个十进制数的二进制表示有多少位1&#xff1f; 1 遍历法&#xff08;递归或非递归&#xff09; 使用循环按位统计1的个数。 2 哈希查表法 利用一个数组或哈希生成一张表&#xff0c;存储不同二进制编码对应的值为1的二进制位数&#xff0c;那么在使用时&#xff0c;只…

MIT-BEVFusion系列八--onnx导出2 spconv network网络导出

这里写目录标题 export-scn.py加载模型设置每层的精度属性初始化输入参数导出模型model.encoder_layers 设置初始化参数设置 indice_key 属性更改 lidar backbone 的 forward更改lidar网络内各个层的forward带参数装饰器&#xff0c;钩子函数代码使用装饰器修改forward举例 跟踪…

GPU芯片逆势扩张,NVIDIA成为2023年全球芯片的唯一赢家

市调机构Gartner发布数据指出2023年全球诸多芯片行业都在下滑&#xff0c;唯一取得增长的仅有GPU/AI芯片&#xff0c;GPU芯片的市场规模增加了一倍&#xff0c;而领头羊NVIDIA无疑成为最大的赢家。 从2022年下半年以来&#xff0c;全球芯片行业就已步入供给过剩的阶段&#xff…

HarmonyOS—状态管理概述

在前文的描述中&#xff0c;我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面&#xff0c;就需要引入“状态”的概念。 图1 效果图 上面的示例中&#xff0c;用户与应用程序的交互触发了文本状态变更&#xff0c;状态变更引起了UI渲染&#xff0c;UI从“He…

C++中对象的构造与析构顺序

一、对象的构造顺序 对象的构造&#xff0c;先被创建的对象&#xff0c;先被构造&#xff0c;先调用其构造函数 class A { private:int _a 0; public://构造函数A(int a 0){_a a;cout << "A(int a 0)" << " " << _a << endl…

【计算机网络】网际协议——互联网中的转发和编址

编址和转发是IP协议的重要组件 就像这个图所示&#xff0c;网络层有三个主要组件&#xff1a;IP协议&#xff0c;ICMP协议&#xff0c;路由选择协议IPV4 没有选项的时候是20字节 版本&#xff08;号&#xff09;&#xff1a;4比特&#xff1a;规定了IP协议是4还是6首部长度&am…

【Redis】Redis

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 Nosql为什么使用Nosql什么是NosqlNosql特点 Redis入门windows安装Linux安装 Nosql 为什么使用N…

盐构造发育的动力学机制

盐构造可以由以下6 种机制触发引起(图 2)[18] &#xff1a;①浮力作用&#xff1b;②差异负载作用&#xff1b;③重力扩张作 用&#xff1b;④热对流作用&#xff1b;⑤挤压作用&#xff1b;⑥伸展作用。盐体 的塑性流动和非常规变形是盐构造的主要特点,岩 盐有时在几百m 深处就…

Linux第一个小程序-进度条

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、回车和换行 二、行缓冲区概念 三、倒计时 四、进度条代码 版本一&#xff1a; ​编辑 版本二&#xff1a; 总结 前言 世上有两种耀眼的光芒&#xff0c;一…

java中的枚举

枚举 枚举类型的概述 关键字&#xff1a;enum 你可以把枚举类型理解成是一个自定义的常量的序列 枚举的语法结构 定义的枚举类型文件 package com.it.xiaosi.demo01;/*** Classname : direction* Description : TODO 枚举* Author : lin_refuelqq.com*/ public enum direct…

关于VIT(Vision Transformer)的架构记录

在VIT模型设计中&#xff0c;尽可能地紧密遵循原始的Transformer模型&#xff08;Vaswani等人&#xff0c;2017年&#xff09;。这种刻意简化的设置的一个优势是&#xff0c;可扩展的NLP Transformer架构及其高效的实现几乎可以即插即用。 图&#xff1a;模型概述。我们将图像分…

Qt实用技巧:QCustomPlot做北斗GPS显示绝对位置运动轨迹和相对位置运动轨迹图的时,使图按照输入点顺序连曲线

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/136131310 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

机器学习入门--LSTM原理与实践

LSTM模型 长短期记忆网络&#xff08;Long Short-Term Memory&#xff0c;LSTM&#xff09;是一种常用的循环神经网络&#xff08;RNN&#xff09;变体&#xff0c;特别擅长处理长序列数据和捕捉长期依赖关系。本文将介绍LSTM模型的数学原理、代码实现和实验结果&#xff0c;并…

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(3)-系统数据集合设计

前言 前几章教程我们把ToDoList系统的基本框架搭建好了&#xff0c;现在我们需要根据我们的需求把ToDoList系统所需要的系统集合&#xff08;相当于关系型数据库中的数据库表&#xff09;。接下来我们先简单概述一下这个系统主要需要实现的功能以及实现这些功能我们需要设计那些…

平时积累的FPGA知识点(10)

平时在FPGA群聊等积累的FPGA知识点&#xff0c;第10期&#xff1a; 41 ZYNQ系列芯片的PL中使用PS端送过来的时钟&#xff0c;这些时钟名字是自动生成的吗&#xff1f; 解释&#xff1a;是的。PS端设置的是ps_clk&#xff0c;用report_clocks查出来的时钟名变成了clk_fpga_0&a…

NX二次开发树列表双击快速进入编辑状态

先将这几个树列表回调注释给解开 int TreeColumn0;//定义一个全局边量记录点击的那一列NXOpen::BlockStyler::Tree::BeginLabelEditState OnBeginLabelEditCallback(NXOpen::BlockStyler::Tree *tree,NXOpen::BlockStyler::Node *node,int columID) {if(columnIDTreeColumnID)…

The method toList() is undefined for the type Stream

The method toList() is undefined for the type Stream &#xff08;JDK16&#xff09; default List<T> toList() { return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray()))); }

磁体发条概念

使用磁体发条&#xff08;也称为磁弹簧或磁蓄能器&#xff09;作为储能装置是一个有趣的概念&#xff0c;它利用电磁感应原理来存储和释放能量。磁体发条的基本原理是通过旋转一个强磁体&#xff0c;使其通过一个线圈的中心&#xff0c;从而在线圈中产生电流。当磁体停止旋转时…

平时积累的FPGA知识点(11)

平时在FPGA群聊等积累的FPGA知识点,第11期: 51 可以把dcp文件封装到自己ip里吗? 解释:不可以 52 fifo的异步复位要做异步复位同步释放吗? 解释:要跟写时钟同步,所以需要在ip外部做一下同步释放 53 vivado报错 Phase 6.1 Hold Fix Iter Phase 6.1.1 Update Timing …