训练营day11(1001) | 第五章 栈与队列

今日内容: 理论基础232.用栈实现队列225. 用队列实现栈20. 有效的括号1047. 删除字符串中的所有相邻重复项

理论基础

栈和队列是STL(C++标准库)中的两个数据结构

栈stack-先进后出;队列queue-先进先出

栈与队列理论1

数据结构问题

1. C++中stack 是容器么?

答:不是。栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可选择的,如vector, deque, list。STL栈和队列不是容器,而被归为容器适配器(container adapter)

stack要求其底层容器需满足如下操作:empty:判空操作;back:获取尾部元素操作; push_back:尾部插入元素操作; pop_back:尾部删除元素操作   (这里的尾部相当于stack的顶部)

2. 我们使用的stack是属于哪个版本的STL?

答:常用SGI STL,该版本下如果没有指定底层实现的话,默认是以deque为栈的底层结构。

3. 我们使用的STL中stack是如何实现的?(队列也是如此

答:栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可选择的,如vector, deque, list,默认使用deque为底层容器。(deque是双向队列,只要封住一端就可实现栈的逻辑)

4. stack 提供迭代器来遍历stack空间么?

答:stack没有迭代器。stack的所有元素进出都必须符合“先进后出”的条件,只有stack顶端的元素,才有机会被外界取用。stack不提供随机访问功能,也不提供迭代器。

初始化栈和队列

std::stack<int, std::vector<int> > third;  // 使用vector为底层容器的栈
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列

232.用栈实现队列

思路

用两个栈,即可模拟队列的功能。队列是输入1-2-3,输出1-2-3;而第一个栈输入1-2-3,输出3-2-1给第二栈,故第二个栈可以输出1-2-3

进队列和进in栈是一样的,所以问题关键是出队列时,要先把in栈数据拿到out栈,再从out栈出

stack基本用法

 代码

class MyQueue {
public:
    stack<int> inStack;
    stack<int> outStack;
    MyQueue() {

    }
    
    void push(int x) {
        inStack.push(x);
    }
    
    int pop() {
        if(outStack.empty()){
            while(!inStack.empty()){
                outStack.push(inStack.top());
                inStack.pop();
            }
        }
        int result = outStack.top();
        outStack.pop();
        return result;
    }
    
    // 与pop()类似,只是查询第一个进入的元素,而不用删除
    int peek() {
        int result = this->pop();
        outStack.push(result);  //因为pop()把元素弹了出去,所以要加回来
        return result;
    }
    
    bool empty() {
        return inStack.empty() && outStack.empty();
    }
};

top()是获取栈的顶头元素,pop()才是把它弹出

peek()与pop()类似,所以尽量采用代码复用的方式而不是粘贴代码,提高美观度

225. 用队列实现栈

思路:用一个队列来实现顺序的颠倒

队列的基本用法

q.push(item)           //将item压入队列尾部
q.pop()                //删除队首元素,但不返回
q.front()              //返回队首元素,但不删除
q.back()               //返回队尾元素,但不删除
q.size()               //返回队列中元素的个数
q.empty()              //检查队列是否为空,如果为空返回true,否则返回false

代码

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

    }
    
    void push(int x) {
        q.push(x);
    }
    
    int pop() {
        // 除最后一个元素外,把每个头部元素添加到尾部
        int size = q.size();
        while(--size){
            q.push(q.front());
            q.pop();
        }
        int result = q.front();
        q.pop();
        return result;
    }
    
    int top() {
        return q.back();

    }
    
    bool empty() {
        return q.empty();
    }
};

20. 有效的括号

栈的经典应用(匹配问题都是栈的强项)

思路

其实只有3种不匹配的情况

1-左括号有多余的情况

括号匹配1

解决:当遍历到左括号时,把对应的右括号放到栈中(为了方便对比匹配),如果遇到右括号,就把栈中的右括号弹出,当遍历结束后,栈中还有元素的话,则说明情况1成立,左括号有多余的情况

 2-括号没有多余,但括号类型没有匹配上

括号匹配2

解决:当遍历到左括号时,把对应的右括号放到栈中(这一点与情况一相同),但当遇到右括号时,要和顶元素去比较是否一样,若不一样,说明情况2成立

3-右括号有多余的情况

括号匹配3

解决:当遍历到左括号时,把对应的右括号放到栈中(这一点与情况一相同),但若还未遍历完,栈就空了,则说明情况3成立

代码

class Solution {
public:
    bool isValid(string s) {
        // 剪枝操作 如果长度为奇数,则一定失败
        if(s.size()%2) return false;

        stack<char> sta;
        for(int i=0; i<s.size(); i++){
            if(s[i] == '(') sta.push(')');
            else if(s[i] == '[') sta.push(']');
            else if(s[i] == '{') sta.push('}');
            // 分别对应情况3 右括号多余 和情况2 类型不匹配
            // 这里写或是因为如果栈为空,则.top()为非法操作
            else if(sta.empty() || sta.top() != s[i]) return false;
            else sta.pop();
        }
        // 对应情况1,如果不为空,则说明左括号多余
        return sta.empty();
    }
};

若长度为奇数,则一定不匹配,可以做剪枝操作

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

栈的经典应用(匹配问题都是栈的强项)

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> sta;
        for(int i=0; i<s.size(); i++){
            // 如果不等于栈顶或者栈为空,则放入
            if(sta.empty() || s[i]!=sta.top()){
                sta.push(s[i]);
            }

            // 如果等于栈顶则弹出栈顶
            else{
                sta.pop();
            }
        }

        // 从栈导出到字符串,并且翻转
        string str="";
        while(!sta.empty()){
            str += sta.top();
            sta.pop();
        }
        reverse(str.begin(), str.end());
        return str;
    }
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值