栈与队列-算法总结

news2024/9/21 11:00:58

目录

基础知识

用栈实现队列

 用队列实现栈

 栈的拿手好戏

删除字符串中的所有相邻重复项

逆波兰表达式求值

滑动窗口最大值

前k个高频元素


基础知识

队列
stackqueue
先进后出先进先出
无迭代器无迭代器
容器设配器容器设配器
vector deque listvector deque list

C++标准库版本

HP STLPJ STLSGI STL

deque是双向的队列,封住一端就是stack

用栈实现队列

利用两个栈实现对队列的进出操作。首先要明确这两个栈分别是进栈,出栈,当队列数据进入之后,就把数据存入进栈,再把进栈数据存入出栈,那么这时出栈再出去的数据就和队列保持一致了。

push

此时在队列中就是把数据存入队列中,那么此时我们就把该数据存入进栈中

pop

此时在队列中是把最开始存入的元素出去,那么我就相当于操作出栈的第一个元素。因此我们先把数据存入进栈,出栈。这时出栈没有数据,为空,因此先判断出栈是否为空,然后把进栈的数据存入

        if(stOut.empty()){
            while(!stIn.empty()){
                stOut.push(stIn.top());
                stIn.pop();
            }
        }

这时,出栈已经有了数据,要出去第一个数据只需要把出栈第一个数据出去

        int result = stOut.top();
        stOut.pop();

peek

返回队列的第一个元素,和pop很像,一个是弹出,一个是返回值,那么就相当于我们不pop,只得到值,只需要在pop之后把数据push进去

    int peek() {
        int res = this->pop(); // 直接使用已有的pop函数
        stOut.push(res); // 因为pop函数弹出了元素res,所以再添加回去
        return res;
    }

232. 用栈实现队列 - 力扣(LeetCode)https://leetcode.cn/problems/implement-queue-using-stacks/submissions/

 用队列实现栈

利用一个队列模拟栈的过程,栈出去的元素类似于把队列前面的元素再插入一次,再把队列最后一个元素出去。

class MyStack {
public:
    queue<int>que;
    MyStack() {

    }
    
    void push(int x) {
        que.push(x);
    }
    
    int pop() {
        int size = que.size()-1;
        while(size--){
            que.push(que.front());
            que.pop();
        }
        int result = que.front();
        que.pop();
        return result;
    }
    
    int top() {
        return que.back();
    }
    
    bool empty() {
        return que.empty();
    }
};

/**
 * 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();
 */

225. 用队列实现栈 - 力扣(LeetCode)https://leetcode.cn/problems/implement-stack-using-queues/submissions/

 栈的拿手好戏

用栈的原因是因为左右括号存在就直接抵消,且存在3种情况。

注意事项:因为我们是遇到左括号插入右括号,这是分别字符串和栈顶元素比价

1.当字符串结束在,栈中还有元素,不匹配

2.当字符串遍历到右括号,且和栈顶不一样,则不匹配

3.当字符串遍历到右括号,且栈为空,则没有对应的左括号,则不匹配。

class Solution {
public:
    bool isValid(string s) {
        stack<char>stk;
        unordered_map<char, char> map = {
            {')', '('},
            {']', '['},
            {'}', '{'}
        };
        for (auto ch : s)
        {
            if (map.count(ch))//判断是不是右括号
            {
                //栈为空,或者栈顶不匹配
                if (stk.empty() || stk.top() != map[ch])
                {
                    return false;
                }
                stk.pop();
            }
            else//找到了左括号
            {
                stk.push(ch);
            }
        }
        return stk.empty();
    }
   
};

删除字符串中的所有相邻重复项

利用一个栈,把数据进行存放,每次放之前判断栈顶是不是一样,一样则不存该元素并且出栈栈顶这个元素,如果不一样则直接存放

        for(auto ch : s){
            if(sta.empty() || sta.top()!=ch){
                sta.push(ch);
            }else{
                sta.pop();
            }
        }

当字符串遍历结束之后,那么sta中保留的就是我们需要的答案,此时只需要出栈就行,但要注意,出栈元素的顺序和输入顺序相反,因此需要reverse

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char>sta;
        for(auto ch : s){
            if(sta.empty() || sta.top()!=ch){
                sta.push(ch);
            }else{
                sta.pop();
            }
        }
        string result = "";
        while(!sta.empty()){
            result += sta.top();
            sta.pop();
        }
        reverse(result.begin(),result.end());
        return result;

    }
};

逆波兰表达式求值

利用一个栈进行存放数,当遇到符号就把栈里面的前两个拿出来进行处理,然后继续存放,直到所有数据

        stack<long long>sta;
        for(int i = 0; i < tokens.size(); i++){
            if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){
                long long num1 = sta.top();
                sta.pop();
                long long num2 = sta.top();
                sta.pop();
                if(tokens[i] == "+") sta.push(num1 + num2);
                if(tokens[i] == "-") sta.push(num2 - num1);
                if(tokens[i] == "*") sta.push(num1 * num2);
                if(tokens[i] == "/") sta.push(num2 / num1);
            }else{
                sta.push(stoll(tokens[i]));
            }
        }

此时数据已经处理结束,只需要把栈顶元素取出来就行

      class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long>sta;
        for(int i = 0; i < tokens.size(); i++){
            if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){
                long long num1 = sta.top();
                sta.pop();
                long long num2 = sta.top();
                sta.pop();
                if(tokens[i] == "+") sta.push(num1 + num2);
                if(tokens[i] == "-") sta.push(num2 - num1);
                if(tokens[i] == "*") sta.push(num1 * num2);
                if(tokens[i] == "/") sta.push(num2 / num1);
            }else{
                sta.push(stoll(tokens[i]));
            }
        }
        int result = sta.top();
        sta.pop();
        return result;
    }
};

滑动窗口最大值

本题思路自己创建一个队列,该队列可以实现

1.每次插入时,如果前面的元素小于当前插入,则把之前的元素就把出队列

2.每次删除时,先判断队列顶端是不是要删的,如果不是则不删,是则删

3.每次返回队列顶端元素,且该元素是队列中最大元素

class Solution {
private:
    class MyQueue{
        public:
        deque<int>que;
        void pop(int values){
            if(!que.empty() && values == que.front()){
                que.pop_front();
            }
        }
        void push(int values){
            while(!que.empty() && values > que.back()){
                que.pop_back();
            }
            que.push_back(values);
        }
        int front(){
            return que.front();
        }
    };

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());
        for(int i=k;i<nums.size();i++){
            que.pop(nums[i-k]);//去除第一个元素
            que.push(nums[i]);//插入新的元素
            ans.push_back(que.front());
        }
        return ans;
    }
};

前k个高频元素

1.利用map记录每个元素和其次数

2.把map数据存放倒小顶堆,而且只放k个,超过k个则直接弹出堆顶,需要注意小顶堆的堆顶是最小的元素

class Solution {
public:
    class mycomparison{
        public:
            bool operator()(const pair<int,int>& Ihs, const pair<int,int>& rhs){
                return Ihs.second > rhs.second;
            }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //先把数据插入map中统计每个数的次数
        unordered_map<int,int>umap;
        for(int i=0;i<nums.size();i++){
            umap[nums[i]]++;
        }
        //定义一个小顶堆,大小为k
        priority_queue<pair<int,int>, vector<pair<int,int>>,mycomparison> pair_que;
        //把map数据插进去,同时只插入k个
        for(unordered_map<int,int>::iterator it =umap.begin();it!=umap.end();it++){
            pair_que.push(*it);
            if(pair_que.size()>k){
                pair_que.pop();
            }
        }
        vector<int>ans(k);
        for(int i=k-1;i>=0;i--){
            ans[i]=pair_que.top().first;
            pair_que.pop();
        }
        return ans;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“dv/dt”和“di/dt”值:这些值的水平对固态继电器有什么影响?

di/dt水平过高是晶闸管故障的主要原因之一。发生这种情况时&#xff0c;施加到半导体器件上的应力会大大超过额定值并损坏功率元件。在这篇新的博客文章中&#xff0c;我们将解释dv/dt和di/dt值的重要性&#xff0c;以及为什么在为您的应用选择固态继电器之前需要考虑它们。 让…

VMware虚拟机安装Win11最详细过程以及遇到的这台电脑无法运行Windows11的问题

准备工作 在使用VMware虚拟机安装Win11之前我们先把准备工作做好&#xff0c;以免后续思绪混乱导致出错。 1. 到VMware官网或点击链接下载正版VMware Workstation 16 Pro。 2. 双击打开安装包&#xff0c;点击下一步。 3. 阅读用户许可协议&#xff0c;勾选我接受许可协议中的…

k8s-二进制部署

文章目录一、环境二、步骤1、安装cfssl工具2、部署etcd集群3、在node节点安装docker组件4、安装flannel组件部署master节点组件部署node节点部署kube-proxy组件三、测试一、环境 角色服务器地址组件master192.168.174.140kube-apiserver&#xff0c;kube-controller-manager&a…

外包出来,朋友内推我去一家公司,问的实在是太...

外包出来&#xff0c;没想到算法死在另一家厂子&#xff0c;自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到8月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有…

2023赏金计划:Coremail SRC漏洞征集与样本奖励火热进行中

赏金活动一&#xff1a;Coremail SRC漏洞奖励计划 01 活动背景 2023年1月&#xff0c;Coremail安全应急响应中心&#xff08;Coremail SRC&#xff09;正式上线启用&#xff0c;面向公众收集安全漏洞信息与安全情报。Coremail SRC旨在联合众多安全专家、白帽子研究员共同发现…

MySQL 运算符及优先级

MySQL 运算符 MySQL 主要有以下几种运算符&#xff1a; 算术运算符比较运算符逻辑运算符位运算符算术运算符 MySQL 支持的算术运算符包括: 运算符作用加法-减法*乘法/ 或 DIV除法% 或 MOD取余 在除法运算和模运算中&#xff0c;如果除数为0&#xff0c;将是非法除数&#x…

分布式事务几种方案

1&#xff09;、2PC 模式 数据库支持的 2PC【2 phase commit 二阶提交】&#xff0c;又叫做 XA Transactions。 MySQL 从 5.5 版本开始支持&#xff0c;SQL Server 2005 开始支持&#xff0c;Oracle 7 开始支持。 其中&#xff0c;XA 是一个两阶段提交协议&#xff0c;该协议…

推荐系统[八]算法实践总结V1:淘宝逛逛and阿里飞猪个性化推荐:召回算法实践总结【冷启动召回、复购召回、用户行为召回等算法实战】

0.前言:召回排序流程策略算法简介 推荐可分为以下四个流程,分别是召回、粗排、精排以及重排: 召回是源头,在某种意义上决定着整个推荐的天花板;粗排是初筛,一般不会上复杂模型;精排是整个推荐环节的重中之重,在特征和模型上都会做的比较复杂;重排,一般是做打散或满足…

Windows 服务器IIS安装,服务器多界面设置方法

当你在使用服务器时是否有遇到这样一个问题&#xff1f;当你正在服务器里进行工作时&#xff0c;突然一个小伙伴在没有告知你的情况下进入了服务器里&#xff0c;导致你服务器失去连接了&#xff0c;这种情况是非常常见的现象。 主要原因就是因为服务器没有安装多界面&#xf…

k8s多节点二进制部署以及Dashboard-UI

一.多Maser集群架构的了解Kubernetes作为容器集群系统&#xff0c;通过健康检查重启策略是实现Pod故障自我修复能力&#xff0c;通过调度室实现Pod分布式部署&#xff0c;并保持预期副本数&#xff0c;根据Node失效状态自动在其他Node拉起Pod&#xff0c;实现了应用层的高可用。…

KUKA机器人_示教器的基本组成结构和功能介绍

KUKA机器人_示教器的基本组成结构和功能介绍 如何操作KUKA机器人? 通过KUKA机器人的手持操作器(KUKA smartPAD),或者叫示教器。 如下图所示, 可以通过示教器的各种按键菜单和触摸屏(手、触摸笔)来操作示教器。 下面对于示教器上的按键菜单的功能进行详细的说明: …

契约开发、测试你知多少?

契约维护的难题 如今微服务凭借其灵活、易开发、易扩展等优势深入人心&#xff0c;不同服务之间的集成和交互日渐繁多且复杂。这些服务之间交互的方式是多样的&#xff0c;常见的有 HTTP 请求和消息队列。在它们交互的过程中&#xff0c;会有服务的版本演进&#xff0c;交互信…

Mysql架构与内部模块

Mysql架构与内部模块 演示环境&#xff1a; MySQL 5.7 存储引擎&#xff1a;InnoDB 一、一条查询SQL是如何执行的&#xff1f; 程序或者工具要操作数据库&#xff0c;第一步跟数据库建立连接。 1、通信协议 首先&#xff0c;MySQL 必须要运行一个服务&#xff0c;监听默认的…

vue - vue中对Vant日历组件(calendar)的二次封装

vue中对vant日历选择器组件实现的的二次封装&#xff1b;主要实现功能如下: 主要功能&#xff1a; 日期区间选择&#xff08;基本&#xff09;&#xff1b;自定义选择器的底部按钮&#xff0c;添加清除时间操作&#xff08;slot插槽&#xff09;&#xff1b;指定默认选中的日期…

一种图片展示的完美方案,图片展示,object-fill

通常一般的处理 <style>.img-container {width: 300px;height: 200px;background: #f60;}img {width: 100%;height: 100%;}</style> </head> <body><div class"img-container"><img src"./行道树.png" alt""&g…

Java之JVM性能初探

一、JVM简介jvm是一种用于计算设备的规范&#xff0c;它是一个虚构出来的机器&#xff0c;是通过在实际的计算机上仿真模拟各种功能实现的。jvm包含一套字节码指令集&#xff0c;一组寄存器&#xff0c;一个栈&#xff0c;一个垃圾回收堆和一个存储方法域。JVM屏蔽了与具体操作…

AWS攻略——使用Public NAT解决私有子网实例访问互联网

文章目录创建NAT网关编辑Private子网路由测试知识点参考资料在《AWS攻略——子网》一文中&#xff0c;我们分别创建了一个Public子网和一个Private子网&#xff0c;并让Public子网中的实例可以SSH登录到Private子网的实例中。 现实场景中&#xff0c;我们可能存在如下需求&…

正版授权的商业级智慧校园源码 SaaS模式带小程序端

一套针对中小学校园研发的商业级智慧校园源码&#xff0c;系统功能强大&#xff0c;代码完整&#xff0c;源码有演&#xff0c;正版授权。 私信了解更多&#xff01; 一、智慧校园系统构成&#xff1a; 1、 SaaS云平台 2、 智慧校园管理平台 3、 小程序教师端 4、 小程序家…

【一文带你看懂什么是VLAN、网关、DNS和子网掩码等 】

很多小伙伴多次问到什么是VLAN、三层交换机、网关、MAC地址、DNS和子网掩码&#xff0c;它们具体的定位和用途。确实&#xff0c;如今网络技术已经覆盖了非常广阔的工作和生活场景&#xff0c;但很多人在日常的应用当中还是不太懂这些知识&#xff0c;今天我们就尝试用比较通俗…

从功能测试进阶自动化测试涨薪7k,终究是逼了自己一把...

绝大多数测试工程师都是从功能测试做起的&#xff0c;工作忙忙碌碌&#xff0c;每天在各种业务需求学习和点点中度过&#xff0c;过了好多年发现自己还只是一个功能测试工程师随着移动互联网的发展&#xff0c;从业人员能力的整体进步&#xff0c;软件测试需要具备的能力要求越…