代码随想录算法训练营第十,十一天|232.用栈实现队列、225.用队列实现栈、20.有效的括号、1047.删除字符串中的所有相邻重复项、LCR 036. 逆波兰表达式求值

文章介绍了如何使用栈和队列数据结构来解决LeetCode中的四个问题:用栈实现队列、用队列实现栈、有效括号判断、删除字符串中的相邻重复项。主要展示了如何通过栈的进栈和出栈操作以及队列的先进先出或后入先出特性来模拟复杂的数据结构操作。
摘要由CSDN通过智能技术生成

232.用栈实现队列

题目描述

题目链接:力扣232.用栈实现队列

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

实现 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的数据依次挪到栈2,再取栈2的顶部数据即可。

将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop 和 peek 操作。

每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。

代码实现

class MyQueue {
private:
    stack<int> inStack, outStack;

    void in2out() {
        while (!inStack.empty()) {
            outStack.push(inStack.top());
            inStack.pop();
        }
    }

public:
    MyQueue() {}

    void push(int x) {
        inStack.push(x);
    }

    int pop() {
        if (outStack.empty()) {
            in2out();
        }
        int x = outStack.top();
        outStack.pop();
        return x;
    }

    int peek() {
        if (outStack.empty()) {
            in2out();
        }
        return outStack.top();
    }

    bool empty() {
        return inStack.empty() && outStack.empty();
    }
};

225.用队列实现栈

题目描述

题目链接:力扣225.用队列实现栈

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

实现 MyStack 类:

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

注意:

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

思路

由于栈的特性是先入先出,在使用队列实现栈时,应满足队列前端的元素最后入栈,可以使用两个队列实现栈的操作,其中 q u e u e 1 queue_1 queue1 用于存储栈内的元素, q u e u e 2 queue_2 queue2 作为入栈的辅助队列。

入栈时,首先将元素入队到 q u e u e 2 queue_2 queue2,然后将 q u e u e 1 queue_1 queue1 的元素全部出队并入队到 q u e u e 2 queue_2 queue2,此时 q u e u e 2 queue_2 queue2 的前端元素即为新入栈的元素,再将 q u e u e 1 queue_1 queue1 q u e u e 2 queue_2 queue2 互换,则 q u e u e 1 queue_1 queue1 的元素为栈内的元素即为栈内的元素, q u e u e 1 queue_1 queue1 的前端和后端分别对应栈顶和栈底。

判断栈空时,只需要判断 q u e u e 1 queue_1 queue1 是否为空即可。

代码实现

class MyStack {
public:
    queue<int> queue1;
    queue<int> queue2;

    /** Initialize your data structure here. */
    MyStack() {

    }

    /** Push element x onto stack. */
    void push(int x) {
        queue2.push(x);
        while (!queue1.empty()) {
            queue2.push(queue1.front());
            queue1.pop();
        }
        swap(queue1, queue2);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int r = queue1.front();
        queue1.pop();
        return r;
    }
    
    /** Get the top element. */
    int top() {
        int r = queue1.front();
        return r;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return queue1.empty();
    }
};

20.有效的括号

题目描述

题目链接:力扣20.有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

思路

顺序遍历字符串,碰到左括号就入栈,碰到右括号就判断和栈顶元素是否匹配,匹配就出栈,不匹配就说明字符串无效。

代码实现

class Solution {
public:
    bool isValid(string s) {
        char stack[10001];
        int top =0;
        for (int i = 0; s[i]; ++i) {
            if (s[i] == '(' || s[i] == '[' || s[i] == '{') stack[top++] = s[i];
            else {
                if ((--top) < 0)                      return false;//先减减,让top指向栈顶元素
                if (s[i] == ')' && stack[top] != '(') return false;
                if (s[i] == ']' && stack[top] != '[') return false;
                if (s[i] == '}' && stack[top] != '{') return false;
            }
        }
        return (!top);//防止“【”这种类似情况
    }
};

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

题目描述

题目链接:力扣1047. 删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

思路

和括号匹配问题类似,只要顺序遍历字符串,碰到和栈顶元素不一样就入栈,一样就出栈,最后从栈底顺序输出即可。

代码实现

class Solution {
public:
    string removeDuplicates(string s) {
        char stack[100005];
        int top = 0;
        for(int i = 0; i < s.size(); i++){
            if(top == 0 || s[i] != stack[top - 1]){
                stack[top++] = s[i];
            }
            else if(s[i] == stack[top - 1]){
                top --;
            }
        }
        string res;
        for(int i = 0; i < top; i++){
            res += stack[i];
        }
        return res;
    }
};

LCR 036. 逆波兰表达式求值

题目描述

题目链接:力扣LCR 036.逆波兰表达式求值

根据 逆波兰表示法,求该后缀表达式的计算结果。

有效的算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

  • 整数除法只保留整数部分。
  • 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

思路

根据逆波兰表达式的计算方法,很容易想到栈的数据结构。

顺序遍历表达式,如果是数字就入栈,如果是算符就取出栈顶两个元素,按算符计算,再将结果入栈,如此遍历结束,栈中应只剩一个元素,表达式的值。

注意:取出栈顶两个元素时,注意两个数的操作顺序,对除法会有影响。

代码实现

class Solution {
public:
    int string2int(string s){
        int i = 0;
        if(s[0] == '-') i = 1;

        int num = 0;
        while(i < s.size()){
            num = num * 10 + s[i] - '0';
            i++;
        }
        if(s[0] == '-') return -num;
        return num;
    }

    bool isOperator(string s){
        return s == "+" || s == "-" || s == "*" || s == "/";
    }

    int evalRPN(vector<string>& tokens) {
        int stack[10004], top = 0;
        for(int i = 0; i < tokens.size(); i++){
            if(top == 0 || !isOperator(tokens[i])){
                stack[top++] = string2int(tokens[i]);
            }
            else if(isOperator(tokens[i])){
                int t = 0;
                int b = stack[--top], a = stack[--top];
                if(tokens[i] == "+") t = a + b;
                if(tokens[i] == "-") t = a - b;
                if(tokens[i] == "*") t = a * b;
                if(tokens[i] == "/") t = a / b;

                stack[top++] = t;
            }
        }
        return stack[--top];
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值