代码随想录:栈与队列2-3

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)

class MyQueue {

    Stack<Integer> in;
    Stack<Integer> out;
    public MyQueue() {
        in = new Stack<>();
        out = new Stack<>();

    }
    
    public void push(int x) {
        in.push(x);  //输入栈模拟队列的输入
    }
    
    public int pop() {
        if(out.isEmpty()){   //输出栈模拟队列的输出
            while(!in.isEmpty()){  //如果输入栈为空,把输入栈元素全部移入输出栈
                out.push(in.pop());  
            }
        }
        int result = out.pop();
        return result;
    }
    
    public int peek() {
        int result = this.pop(); //函数复用,调用上面的pop
        out.push(result);  //把pop的元素push回去
        return result;
    }
    
    public boolean empty() {
        return in.isEmpty() && out.isEmpty();
    }
}

/**
 * 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();
 * boolean param_4 = obj.empty();
 */

代码(版本2)

class MyQueue {

    Stack<Integer> in;
    Stack<Integer> out;
    public MyQueue() {
        in = new Stack<>();
        out = new Stack<>();

    }
    
    public void push(int x) {
        in.push(x);  //输入栈模拟队列的输入
    }
    
    public int pop() {
        tackle();  //把out栈操作成我们想要的状态,即满足队列输出顺序
        int result = out.pop();
        return result;
    }
    
    public int peek() {
        tackle();  把out栈操作成我们想要的状态,即满足队列输出顺序
        int result = out.peek();
        return result;
    }
    
    public boolean empty() {
        return in.isEmpty() && out.isEmpty();
    }

    //用于处理输入栈in到输出栈out的元素移动
    public void tackle(){
        //如果out是空,要把in的所有元素移过去
        if(out.isEmpty()){
            while(!in.isEmpty()){
                out.push(in.pop());
            }
        }
        //如果out不是空,可以直接输出,不需要移动元素
        else{
            return;
        }
    }
}

/**
 * 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();
 * boolean param_4 = obj.empty();
 */

总结

1.思路

        队列的队尾输入元素,队头输出元素。那么,可以用一个输入栈,模拟队列的输入,用一个输出栈,模拟队列的输出。而且,输入栈的元素和队列的队尾输入元素顺序一致。但输出栈的元素如果要和输入顺序一致,需要从输入栈从移入。下面举例说明了如何用输入栈和输出栈模拟队列,以及两个栈的元素如何移动。

2.算法流程

(1)push函数

        直接in.push(x)即可,把队列的队尾元素push到in栈内。

(2)pop函数

        由于输入栈的元素顺序不是我们想要的输出顺序,因此要把in栈的元素pop出来再push到out栈里。

        首先,判断当前的out栈是否为空。为什么要做这个判断?因为如果out是空,说明out中没有元素输出了,要把in中的所有元素移动过来。因此,如果out为空,就要用while循环判断in,只要in栈不为空,需要一直执行out.push(in.pop())语句。

        此时,out栈就处理到我们希望的状态了,要么out本身有元素可以直接输出,要么out没有元素但是已经把in的所有元素拿过来了。此时就可以返回out.pop()。

(3)peek函数

        peek函数用于获取队头的元素,即获取输出栈的元素。和pop函数的原理一致,需要先把out栈就处理到我们希望的状态。然后此时就可以返回out.peek()

(4)isEmpty函数

        很简单,只有满足in和out同时为空,才能返回true。

3.注意点

        这里我给了两个版本的Java代码。

        版本一:直接把“out栈处理到我们希望的状态”功能的代码写在了pop函数里,在peek函数中,直接用this指针调用pop函数获取队头元素,再把队头元素push回去即可。

        版本二:把“out栈处理到我们希望的状态”功能的代码封装到了单独的tackle函数里。因此在pop函数中,先调用tackle处理out和in的状态,返回out.pop()即可。在peek函数里,先调用tackle处理out和in的状态,返回out.peek()即可。

        两个版本相比较,我觉得版本一在第一遍写代码时更容易写出来,但是版本二的代码逻辑更清晰,相当于把pop和peek需要的相同功能——处理out和in栈的状态,单独封装成函数,然后在单独调用。如果有能力,还是写版本二更好,方便后续对tackle函数进行修改。

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(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

代码(一个队列实现)

class MyStack {

    Queue<Integer> que;

    public MyStack() {
        que = new LinkedList<>(); //双向链表
    }
    
    public void push(int x) {
        que.add(x);  //add添加到列表末尾,模拟栈的输入
    }
    
    public int pop() {
        tackle(); //如果队列元素大于1,要把前面的元素依次移到队尾
        int result = que.poll();  //poll用于删除队头元素
        return result;
    }
    
    public int top() {
        //以123为例,要想获取队尾元素3,先移动成312,把队尾元素3给poll,变成12,获取到3
        //再把3重新add到队尾,变成123,恢复初始状态
        tackle(); //如果队列元素大于1,要把前面的元素依次移到队尾
        int result = que.poll(); //poll删除队头元素,并返回队头元素
        que.add(result);  //把删除的元素重新加到队尾,
        return result;
    }
    
    public boolean empty() {
        return que.isEmpty();
    }

    //如果队列元素大于1,要把前面的元素依次移到队尾
    public void tackle(){
        int size = que.size();
        while(size-- > 1){
            que.add(que.poll());
        }
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

总结

1.思想

        要想用一个队列实现栈,首先考虑栈的输入123,等价于队列的末尾输入123。然后考虑栈的输出321,是从栈顶(队列末尾)开始输出即先输出3。因此,关键是要把队列的元素进行移动调整,把末尾元素3移动到队头,把前面的元素12移动到队尾。下图展示了栈输入123输出321,在一个队列中如何进行输入和输出。

2.算法流程

(1)push函数

        直接用add函数,把元素放到队列的末尾即可

(2)pop函数

        首先要明确,栈中的pop元素是在栈顶的,也是在队列的末尾的。由于队列只能在队头输出,因此我们把队尾元素移动队头不就好了。(队列123,要pop3,就把3移到最前面,变成312)

        因此,要想pop队列的末尾元素3,那我们就先把前面的size-1个元素12移动到队尾,使得队尾元素移到队头,这时队列是312,再调用poll函数,pop出元素3。

(3)top函数

        top函数是要返回栈顶元素,也是在队列的末尾。因此,我们操作的函数队列的队尾元素。那么可以和pop函数一样,初始队列状态是123,要想获取元素3,先把队尾元素3移到前面变成312,把队头元素pop出去获取到元素3,再把3重新add到队尾,变成123恢复队列初始状态。

(4)isEmpty函数

        直接判断队列是否为空即可。

3.注意点

        因为pop和top函数有相同的功能,即要把前size-1个元素移到队尾使得队尾元素移动到队头。因此我用了tackle函数进行了封装,实现队列的元素移动。然后,在pop函数里,先调用tackle把队尾元素移到前面,在进行poll即可。在top函数里,先调用tackle把队尾元素移到前面,在进行poll,最后把poll的元素重新add到队尾即可。

4.语法点

(1)queue.poll():用于删除的头部元素

(2)queue.add(x):用于在尾部添加元素

(3)queue.isEmpty():用于判断是否为空

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

守岁白驹hh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值