【C++】stack&queue系列力扣刷题日志(232.用栈实现队列、225.用队列实现栈、155.最小栈、牛客JZ31.栈的压入弹出序列、150.逆波兰表达式求值)

目录

232.用栈实现队列

225.用队列实现栈

155.最小栈

牛客JZ31.栈的压入、弹出序列

150.逆波兰表达式求值


232.用栈实现队列

题目:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

假设有这样一个队列,队首元素为1,队尾元素为5 。

我们用两个栈来分别模拟入队和出队操作:

入队时,就将数据压入栈1,此时栈顶时队尾元素;出队时,将栈1的元素全部压入栈2中,此时栈顶是队首元素,再进行出栈操作,这样就模拟实现了队列的先入先出。

注意:当出队栈为空时,才需要将入队栈元素压入

 解答:

class MyQueue {
public:
    MyQueue() {
        while(!_push.empty()){
            _push.pop();
        }
        while(!_pop.empty()){
            _pop.pop();
        }
    }
    
    void push(int x) {
        _push.push(x);
    }
    
    int pop() {
        if(_pop.empty()){
            while(!_push.empty()){
                _pop.push(_push.top());
                _push.pop();
            }
        }
        int ret = _pop.top();
        _pop.pop();
        return ret;
    }
    
    int peek() {
        if(_pop.empty()){
            while(!_push.empty()){
                _pop.push(_push.top());
                _push.pop();
            }
        }
        return _pop.top();
    }
    
    bool empty() {
        if(_push.empty() && _pop.empty())
            return true;
        return false;
    }
private:
    stack<int> _push;
    stack<int> _pop;
};

225.用队列实现栈

题目:

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsize 和 is empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

假设入栈5个元素,栈顶元素是5。 

                                                       

我们将这五个元素全部排进队列1,此时栈顶元素在队尾;当我们需要出栈时,就将除队尾元素之外的全部元素排进队列2中,此时栈顶元素来到了队首,再进行出队,这样就模拟实现了栈的后入先出。

 解答:

class MyStack {
public:
    MyStack() {
        while(!_q.empty()){
            _q.pop();
        }
    }
    
    void push(int x) {
        _q.push(x);
    }
    
    int pop() {
        int ret = _q.back();
        queue<int> tmp;
        while(_q.size() != 1){
            tmp.push(_q.front());
            _q.pop();
        }
        _q.pop();
        while(!tmp.empty()){
            _q.push(tmp.front());
            tmp.pop();
        }
        return ret;
    }
    
    int top() {
        return _q.back();
    }
    
    bool empty() {
        return _q.empty();
    }
private:
    queue<int> _q;
};

155.最小栈

题目:

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,vector和list都可以,但是题目要求能在常数时间内检索到最小元素,所以我们选择vector:

class MinStack {
public:
    MinStack() {
        _stack.clear();
    }

    void push(int val) {
        _stack.push_back(val);
    }

    void pop() {
        _stack.pop_back();
    }

    int top() {
        return _stack.back();
    }

    int getMin() {
        vector<int> temp(_stack);
        sort(temp.begin(), temp.end());
        return temp[0];
    }
private:
    vector<int> _stack;
};

牛客JZ31.栈的压入、弹出序列

题目:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

1. 0<=pushV.length == popV.length <=1000

2. -1000<=pushV[i]<=1000

3. pushV 的所有数字均不相同

我们需要一个stack栈来演示压栈过程。

定义两个迭代器,分别指向两个vector的首元素,iterator_pop指向的元素就是下一个出栈的元素,Iiterator_push指向的元素就是下一个入栈的元素,当两者指向的元素值不同时,就继续入栈,并挪动iterator_push;当两者指向值相同时就表示需要出栈,出栈后挪动iterator_pop。

如果最后iterator_pop来到了容器尾,同时stack中没有元素(全部出栈),就说明vector_pop是vector_piush的弹出序列

是弹出序列的情况:

 

不是弹出序列的情况:

 

当然,两个序列如果元素个数不一致,就肯定不是压入、弹出序列

解答:


bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
    if (pushV.size() != popV.size())
        return false;
    auto push = pushV.begin();
    auto pop = popV.begin();
    stack<int> s;
    while (pop != popV.end()) {
        if (s.size() == 0 || s.top() != *pop) {
            s.push(*push);
            ++push;
        }
        if(s.top() == *pop) {
            s.pop();
            ++pop;
        }
    }
    if (s.size())
        return false;
    return true;
}
};

150.逆波兰表达式求值

题目:

 

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

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

注意:

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

假设字符串数组为: ["2","1","+","3","*"]

我们遍历这个数组,当遇到运算符"+"时,需要对“+”之前的两个数进行“+”操作,遇到“*”运算符时,需要将“3”以及前面相加的结果进行“*”操作,转换成算数表达式:((2 + 1) * 3) = 9。

可以观察到,每次遍历到运算符时,需要将连同运算符及其前两个数的三个字符进行算数操作,并将结果保存到当前遍历位置,这不就是我们熟悉的入栈出栈的操作吗,这题我们用stack来解决。

遍历数组,依次将字符入栈,遇到运算符就将三个字符出栈,并转化成算数表达式运算,之后将结果以字符形式继续入栈,继续遍历数组,直到遍历结束。

解答:

class Solution {
public:

int evalRPN(vector<string>& tokens) {
    stack<string> s;
    string ope;
    int left, right;
    auto push = tokens.begin();
    s.push(*push);
    ++push;
    while (1) {
        if (s.size() == 1 && push == tokens.end())
            return std::stoi(s.top());
        if (s.top() != "+" && s.top() != "-" && s.top() != "*" && s.top() != "/") {
            s.push(*push);
            ++push;
        }
        else {
            ope = s.top();
            s.pop();
            right = std::stoi(s.top());
            s.pop();
            left = std::stoi(s.top());
            s.pop();

            if (ope == "+")
                s.push(to_string(left + right));
            if (ope == "-")
                s.push(to_string(left - right));
            if (ope == "*")
                s.push(to_string(left * right));
            if (ope == "/")
                s.push(to_string(left / right));

            }
        }
    }

};

熟练掌握stack和queue容器适配器,对解决一些特定问题有很大帮助。

以上就是我整理的一些关于栈和队列的oj题解,欢迎在评论区留言,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谁在夜里看海.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值