【LeetCode刷题】Day09 栈与队列基础Ⅰ

文章详细介绍了如何使用两个栈实现一个队列,以及如何用两个队列实现一个栈,分别给出了Python和C++的代码示例,并强调了在实现过程中需要注意的数据结构规则和代码复用的重要性。同时,提到了在LeetCode上的相关题目作为实践案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

栈与队列印象不太深刻了,记得之前学的时候应该用C自己实现过栈,队列,不过忘记是用数组还是链表写的了,也忘记怎么写的了…
一刷用python:python栈与队列实现python栈与队列内部实现
二刷学C++:C++栈与队列内部实现

LeetCode232-用栈实现队列

题目描述:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 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(双端队列)来模拟一个栈,只要是标准的栈操作即可
输入
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出
[null, null, null, 1, 1, false]
解释
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
题目链接https://leetcode.cn/problems/implement-queue-using-stacks/

解题思路

  • 需要两个栈一个输入栈,一个输出栈
  • 在push数据的时候,只要数据放进输入栈就好
  • 在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据即可
  • 队列为空:进栈和出栈都为空
class MyQueue:

    def __init__(self):
        """
        in主要负责push,out主要负责pop
        """
        self.stack_in = []
        self.stack_out = []


    def push(self, x: int) -> None:
        """
        有新元素进来,就往in里面push
        """
        self.stack_in.append(x)


    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        if self.empty():
            return None
        
        if self.stack_out:
            return self.stack_out.pop()
        else:
            for i in range(len(self.stack_in)):
                self.stack_out.append(self.stack_in.pop())
            return self.stack_out.pop()


    def peek(self) -> int:
        """
        Get the front element.
        """
        ans = self.pop()
        self.stack_out.append(ans)
        return ans


    def empty(self) -> bool:
        """
        只要in或者out有元素,说明队列不为空
        """
        return not (self.stack_in or self.stack_out)

class MyQueue(object):

    def __init__(self):
        self.s1 = [];
        self.s2 = [];

    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        self.s1.append(x);

    def pop(self): 
    # 把s1栈中的所有元素放进s2中
    # pop栈s2中第一个元素,即实现先进先出
    # 再把s2中的元素放回s1中 
    # 这样的写法不如随想录中写法,因为其实把s2元素放回s1中是没有必要的
    # pop一次下次再pop的话还得再进行s1放入s2,多了一步
        """
        :rtype: int
        """
        if self.empty(): return None;
        while(len(self.s1) != 0):
            self.s2.append(self.s1.pop());
        res = self.s2.pop();
        while(len(self.s2) != 0):
            self.s1.append(self.s2.pop());
        return res;


    def peek(self):
    # 这里没有复用pop,以后要注意代码复用
        """
        :rtype: int
        """
        if self.empty(): return None;
        while(len(self.s1) != 0):
            self.s2.append(self.s1.pop());
        res = self.s2.pop();
        self.s1.append(res);
        while(len(self.s2) != 0):
            self.s1.append(self.s2.pop());
        return res;


    def empty(self):
        """
        :rtype: bool
        """
        if len(self.s1) == 0: return True;
        else: return False;

注意
peek()的实现,直接复用了pop(), 要不然,对stOut判空的逻辑又要重写一遍。在工业级别代码开发中,最忌讳的就是 实现一个类似的函数,直接把代码粘过来改一改就完事了。一定要懂得复用,功能相近的函数要抽象出来,不要大量的复制粘贴,很容易出问题!

心得体会

力扣不让调用第三方库,一开始不知道,一直想用lifoqueue,后来发现报错,以后要注意这一点。
栈和队列等数据结构可以用数组(列表)或者链表、双向队列来做,按照栈、队列的规则去做即可。

LeetCode225-用队列实现栈

题目描述:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
输入
[“MyStack”, “push”, “push”, “top”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出
[null, null, null, 2, 2, false]
解释
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
题目链接https://leetcode.cn/problems/implement-stack-using-queues/

解题思路

  • 两个队列实现栈
  • 一个队列实现栈

1 两个队列实现栈

  • 队列是先进先出的规则,把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并没有变成先进后出的顺序,故一个输入队列,一个输出队列是不可以的
  • 用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1
# 用list实现,没将que2导回que1,而是que1,que2互作备份
class MyStack(object):

    def __init__(self):
        self.q1 = [];
        self.q2 = [];

    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        self.q1.append(x);


    def pop(self):
        """
        :rtype: int
        """
        if self.empty(): return None;
        if len(self.q1) != 0:
            while(len(self.q1) > 1):
                self.q2.append(self.q1.pop(0));
            return self.q1.pop(0);
        else:
            while(len(self.q2) > 1):
                self.q1.append(self.q2.pop(0));
            return self.q2.pop(0);


    def top(self):
        """
        :rtype: int
        """
        if self.empty(): return None;
        res = self.pop();
        self.push(res);
        return res;


    def empty(self):
        """
        :rtype: bool
        """
        if len(self.q1) == 0 and len(self.q2) == 0: 
            return True;
        else: 
            return False;

from collections import deque

class MyStack:

    def __init__(self):
        """
        Python普通的Queue或SimpleQueue没有类似于peek的功能
        也无法用索引访问,在实现top的时候较为困难。

        用list可以,但是在使用pop(0)的时候时间复杂度为O(n)
        因此这里使用双向队列,我们保证只执行popleft()和append(),因为deque可以用索引访问,可以实现和peek相似的功能

        in - 存所有数据
        out - 仅在pop的时候会用到
        """
        self.queue_in = deque()
        self.queue_out = deque()

    def push(self, x: int) -> None:
        """
        直接append即可
        """
        self.queue_in.append(x)


    def pop(self) -> int:
        """
        1. 首先确认不空
        2. 因为队列的特殊性,FIFO,所以我们只有在pop()的时候才会使用queue_out
        3. 先把queue_in中的所有元素(除了最后一个),依次出列放进queue_out
        4. 交换in和out,此时out里只有一个元素
        5. 把out中的pop出来,即是原队列的最后一个
        
        tip:这不能像栈实现队列一样,因为另一个queue也是FIFO,如果执行pop()它不能像
        stack一样从另一个pop(),所以干脆in只用来存数据,pop()的时候两个进行交换
        """
        if self.empty():
            return None

        for i in range(len(self.queue_in) - 1):
            self.queue_out.append(self.queue_in.popleft())
        
        self.queue_in, self.queue_out = self.queue_out, self.queue_in    # 交换in和out,这也是为啥in只用来存
        return self.queue_out.popleft()

    def top(self) -> int:
        """
        1. 首先确认不空
        2. 我们仅有in会存放数据,所以返回第一个即可
        """
        if self.empty():
            return None
        
        return self.queue_in[-1]


    def empty(self) -> bool:
        """
        因为只有in存了数据,只要判断in是不是有数即可
        """
        return len(self.queue_in) == 0

2 一个队列实现栈

  • 一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了
class MyStack:

    def __init__(self):
        self.que = deque()

    def push(self, x: int) -> None:
        self.que.append(x)

    def pop(self) -> int:
        if self.empty():
            return None
        for i in range(len(self.que)-1):
            self.que.append(self.que.popleft())
        return self.que.popleft()

    def top(self) -> int:
        if self.empty():
            return None
        return self.que[-1]

    def empty(self) -> bool:
        return not self.que

3 心得体会

一开始写的代码直接pop最后一个元素了,不符合先进先出的规律,是不对的
后来写了两个队列实现的,但是一个队列实现的也很好想
注意:随想录里面用的是双向队列,原因是list的pop(0)复杂度是O(n)。但是deque的底层实现我理解为链表,因此在pop头元素的时候,复杂度为O(1)。资料:STL各容器的底层实现及其优缺点

总结

用栈构建队列,队列构建栈并不难,写的时候注意用的数据结构需要严格符合栈、队列的进出规则
要对栈、队列的基本操作非常熟悉,需要会自己实现栈、队列
实现中运用list或者deque即可,要对栈、队列的基本操作非常熟悉,一般list常用的方法是append(),pop();deque常用方法是popleft(),append()
需要充分了解代码中数据结构的底层实现,会分析自己写的代码的复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值