Day9 232.用栈实现队列 225. 用队列实现栈 20. 有效的括号 1047. 删除字符串中的所有相邻重复项

62 阅读5分钟

232. 用栈实现队列 - 力扣(LeetCode)

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(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(双端队列)来模拟一个栈,只要是标准的栈操作即可。

232.栈实现队列.png

  1. push的对象永远是stack_in
  2. pop的对象永远是stack_out
  3. 只有stack_out为空时,才会获取stack_in的元素
  • stack_out非空时,不需要stack_in补充也能完成pop
  • stack_out非空时,获取stack_in的元素只能加在栈顶,而他们是晚入队的元素,在栈顶会早出队,不符合队列规则
  1. 获取stack_in的元素时必须完全获取
  • 需要stack_in的元素说明下一个pop的对象是stack_in栈底的元素,如果全部入栈stack_out,后续pop全乱套
class MyQueue {
public:
    stack<int> stackin;
    stack<int> stackout;
    MyQueue() {
        
    }
    
    void push(int x) {
        stackin.push(x);//push的对象永远是stack_in
    }
    
    int pop() {
        if(stackout.empty()){  //如果stackout空,从stackin里获取所有元素
            while(stackin.empty()==0){
                stackout.push(stackin.top());
                stackin.pop();
            }
        }
        int res = stackout.top();
        stackout.pop();//pop的对象永远是stack_out
        return res;
    }
    
    int peek() {//复用。先删后补
        int res = this->pop();
        stackout.push(res);
        return res;
    }
    
    bool empty() {
        return stackin.empty()&&stackout.empty();
    }
};

关于初见这题,我自己的想法

还是要用到第二个栈,像是两个杯子,stack1先倒给stack22倒掉栈顶(也就是1的栈底),再倒回给1。空间复杂度是一样的,但时间复杂度更高,高了不少。由于是自己想到的,还是写出来记录一下。

232.栈实现队列之笨一点的.png 注意 如果用这种方法,peek()无法先调用pop()再调用push()补回去,因为始终只有一个栈,stack2只是相当于一个交换两数时用到的temp。完成pop()后,stack2是空栈,stack1删除了栈底元素且没法直接补回栈底元素。

但处理逻辑跟pop()一模一样,只是少了删除stack2栈顶的这一步(第二十行),只需要记录即可。

class MyQueue {
public:
    stack<int> stack1;
    stack<int> stack2;//创建一个栈,来回倒

    MyQueue() {
        
    }
    
    void push(int x) {
        stack1.push(x);
    }
    
    int pop() {
        while(stack1.empty()==0){
            stack2.push(stack1.top());
            stack1.pop();
        }
        int ans = stack2.top();//记录栈顶元素
        stack2.pop();
        while(!stack2.empty()){
            stack1.push(stack2.top());
            stack2.pop();
        }
        return ans;
    }
    
    int peek() {
        stack<int> stack2;//创建一个栈,来回倒
        while(!stack1.empty()){
            stack2.push(stack1.top());
            stack1.pop();
        }
        int ans = stack2.top();//记录栈顶元素
        while(!stack2.empty()){
            stack1.push(stack2.top());
            stack2.pop();
        }
        return ans;
    }
    
    bool empty() {
        return stack1.empty();
    }
};

225. 用队列实现栈 - 力扣(LeetCode)

请你仅使用两个队列实现一个后入先出(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(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

一次AC^_^

栈顶就是队尾,如果执行pop,stack会删除栈顶,对应到队列就是队尾元素。因此应想办法让队尾元素插队到队首,并保持其他元素相对位置不变。(第一变第二、倒二变倒一)

225.队列实现栈.png

class MyStack {
public:
    queue<int> q;
    MyStack() {
        
    }
    
    void push(int x) {
        q.push(x);
    }
    
    int pop() {
        int depth = q.size();//栈顶等同于队尾
        while(--depth){ //除队尾,其余元素出队再入队,等同于绕圈
            q.push(q.front());
            q.pop();
        }
        //此时,绕圈前的队尾在队首,其他元素都已套圈第二次入队排在后面
        int result = q.front();
        q.pop();
        return result;
    }
    
    int top() {
        int stack_top_element = this->pop();
        q.push(stack_top_element);
        return stack_top_element;
    }
    
    bool empty() {
        return q.empty();
    }
};

20. 有效的括号 - 力扣(LeetCode)

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

有效字符串需满足:

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

之前做过,接受右括号会执行stack.top()查看当前元素和栈顶元素是否匹配。当第一个元素就是右括号时,栈为空,stack.top()会报错,应该先检查栈是否为空。除此之外一次写对^_^

class Solution {
public:
    bool isValid(string s) {
        stack<char> stack;
        for(char i:s){
            if(i=='['||i=='('||i=='{'){//左括号入栈
                stack.push(i);
            }
            else{
                if(stack.empty()) return false;//【就是这里,记得先判断是否为空】
                else if(couple(stack.top())==i) stack.pop();
                else return false;//【栈非空,遇到右括号且不与栈顶元素匹配,最后不可能全部匹配】
            }
        }
        return stack.empty();
    }

    char couple(char in){
        if(in == '[') return ']';
        else if(in == '(') return ')';
        else return '}';
    }
};

1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

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

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

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

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> stack;
        for(char i : s){
            if(stack.empty()){//如果空栈,直接入栈
                stack.push(i);
            }
            else{
                if(i==stack.top()){
                    stack.pop(); //如果连连看成功,连同栈顶元素一同删除
                }
                else stack.push(i);//连连看不成功,入栈
            }
        }
        //将栈中元素转为字符串
        int size = stack.size();
        string ans(size,' ');
        for(int i = size-1;i>=0;i--){
            ans[i] = stack.top();
            stack.pop();
        }
        return ans;
    }
};