算法学习Day10 | 栈与队列理论基础、LeetCode 232.用栈实现队列、LeetCode 225. 用队列实现栈

一、栈与队列理论基础

​1、栈

栈是一种后进先出(LIFO)的数据结构。最早进入的元素存放的位置叫作栈底(bottom),最后进入的元素的存放位置叫作栈顶(top)。

栈的主要操作有:

  • 入栈(push):在栈顶添加一个元素。
  • 出栈(pop):删除并返回栈顶的元素。如果栈为空,则此操作无效。
  • 查看栈顶(peek):返回栈顶的元素但不删除。如果栈为空,则此操作无效。
  • 检查栈是否为空(is_empty):返回一个布尔值,表示栈是否为空。

2、队列(Queue)

队列是一种先进先出(FIFO)的数据结构。第一个添加的元素总是第一个被删除的。就像排队一样,最早排队的人将是第一个被服务的。队列的出口端叫作队头(front),队列的入口端叫作队尾(rear)。

队列的主要操作有:

  • 入队(enqueue):在队列的尾部添加一个元素。
  • 出队(dequeue):删除并返回队列的头部元素。如果队列为空,则此操作无效。
  • 查看队列头部(peek):返回队列的头部元素但不删除。如果队列为空,则此操作无效。
  • 检查队列是否为空(is_empty):返回一个布尔值,表示队列是否为空。

二、 LeetCode 232.用栈实现队列

1、双栈

思路

将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop 和 peek 操作。
每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。

代码

class MyQueue {
private:
    stack<int> inStack;
    stack<int> outStack;
public:
    MyQueue() {
    }
    
    // 向队列中添加一个元素,将其压入 inStack
    void push(int x) {
        inStack.push(x);
    }
    
    // 从队列中移除并返回一个元素
    int pop() {
        // 1.如果 outStack 为空,就将 inStack 中的所有元素弹出并压入 outStack,然后返回 outStack 的栈顶元素并弹出
        // 2.如果 outStack 不为空,直接返回 outStack 的栈顶元素并弹出
        if (outStack.empty()) {
            while (!inStack.empty()) {
                outStack.push(inStack.top());
                inStack.pop();
            }
        }
        int result = outStack.top();
        outStack.pop();
        return result;
    }
    
    // 返回队列的第一个元素
    // 1.如果 outStack 为空,就调用 pop() 方法将inStack里元素压入 outStack。然后返回outStack 的栈顶元素并弹出。再将弹出的元素添加回去
    // 2.如果 outStack 不为空,就调用 pop() 方法返回outStack 的栈顶元素并弹出。再将弹出的元素添加回去
    int peek() {
        int result = this->pop(); 
        outStack.push(result); 
        return result;
    }
    
    // 当 inStack 和 outStack 都为空时返回 true
    bool empty() {
        return inStack.empty() && outStack.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

复杂度分析

时间复杂度: push和empty为 O(1), pop和peek为 O(n)。
空间复杂度: O(n)。

三、 LeetCode 225. 用队列实现栈

1、两个队列

代码

class MyStack {  
public:  
    queue<int> que1;  
    queue<int> que2;  
  
    MyStack() {  
  
    }  
  
    // push 方法,将一个整数 x 添加到队列 que1 的尾部  
    void push(int x) {  
        que1.push(x);  
    }  
  
    // pop 方法,从队列 que1 的头部删除一个元素并返回它。然后将这个元素添加到队列 que2 的尾部,  
    // 再将 que1 的所有元素依次从头部取出并添加到 que2 的尾部,这样就可以保证 que2 的头部元素是最后一个进入 que1 的元素。  
    // 最后返回 que1 的头部元素。这个过程相当于实现了一个后进先出(LIFO)的栈。  
    int pop() {  
        int size = que1.size();
        --size; // 由于堆栈是后进先出(LIFO),因此需要将队列 que1 的元素逆序,以便于取出第一个进入队列的元素  
  
        // 反转队列 que1 中的元素顺序,时间复杂度为 O(n)  
        while (size--) {   
            que2.push(que1.front()); // 将队列 que1 的头部元素压入尾部,相当于将整个队列向后移动一位  
            que1.pop(); // 从队列 que1 中删除头部元素  
        }  
  
        // 此时队列 que2 的头部元素即为最早进入队列 que1 的元素,将其赋给变量 result  
        int result = que2.front();   
        que2.pop(); // 从队列 que2 中删除头部元素,即最早进入队列 que1 的元素  
        que1 = que2;            // 将 que2 的内容复制到 que1,这样 que1 就变成了最新的栈,而 que2 则被清空了。  
        while (!que2.empty()) {   
            que2.pop(); // 清空队列 que2  
        }  
        return result; // 返回最早进入队列 que1 的元素,即最早进入这个栈的元素。  
    }  
  
    // top 方法,返回队列 que1 的尾部元素,即最后一个进入这个栈的元素。此处直接返回其值即可。  
    int top() {  
        return que1.back();  
    }  
  
    // empty 方法,检查队列 que1 是否为空。如果为空则返回 true,否则返回 false。这个方法可以用来检查这个栈是否为空。  
    bool empty() {  
        return que1.empty();  
    }  
};

复杂度分析

时间复杂度:pop为O(n),其他为O(1)
空间复杂度:O(n)

2、一个队列

代码

class MyStack {  
private:  
    queue<int> queue;
public:  
    MyStack() {  
    }  
     
    // push 方法将一个 int 类型的数值 x 压入队列 queue 的尾部  
    void push(int x) {  
        queue.push(x); 
    }  
      
    int pop() {  
        int size = queue.size(); // 获取队列的当前大小,保存在变量 size 中  
        --size; // 由于堆栈是后进先出(LIFO),因此需要将队列的元素逆序,以便于取出第一个进入队列的元素  
  
        // 反转队列中的元素顺序,时间复杂度为 O(n)  
        while (size--) {  
            queue.push(queue.front()); // 将队列的头部元素压入尾部,相当于将整个队列向后移动一位  
            queue.pop(); // 从队列中删除头部元素  
        }  
  
        // 此时队列的头部元素即为最早进入队列的元素,将其赋给变量 result  
        int result = queue.front();   
        queue.pop(); // 从队列中删除头部元素,即最早进入队列的元素  
  
        return result; // 返回最早进入队列的元素  
    }  
      
    int top() {  
        return queue.back(); // 返回队列的尾部元素,即最后一个进入队列的元素,此处返回其值即可  
    }  
      
    bool empty() {  
        return queue.empty(); // 检查队列是否为空,如果为空返回 true,否则返回 false  
    }  
};

复杂度分析

时间复杂度:pop为O(n),其他为O(1)
空间复杂度:O(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值