09. 用两个栈实现队列

链接

https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/
难度: #简单

题目

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

示例 1:

输入: 
["CQueue","appendTail","deleteHead","deleteHead"] 
[[],[3],[],[]] 
输出:[null,null,3,-1]

示例 2:

输入: ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"] 
[[],[],[5],[2],[],[]] 
输出:[null,-1,null,null,5,2]

提示:

  • 1 <= values <= 10000
  • 最多会对 appendTail、deleteHead 进行 10000 次调用

代码框架

class CQueue {

 public CQueue() {

 }

 public void appendTail(int value) {

 }

 public int deleteHead() {

 }
}
  
/**
* Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */

题目解析

该题本质上是实现一个队列,
队列的特点是先进先出,后进后出,
appendTail往队列尾部添加元素,
deleteHead从队列头部删除元素。

使用两个栈tail和head,
栈tail的栈顶是最后加入的整数,
栈head的栈顶是最先加入的整数。

添加整数时往栈tail里面push。

删除整数时从栈head里面pop,
如果pop出来的是null, 则表示栈head为空,
继续检查栈tail是否为空,
如果也为空,则表示队列已经空了, 此时返回-1;
如果不为空,则从栈tail里面pop一个整数,
每pop一个整数就往head里面push,
直到栈tail里面pop出来的是null,
这时再去从栈head里面pop,
即可返回栈顶最先加入的数字。

该题目给出的输入有2行,
第1行是操作的函数,
第2行是对应的入参,
[]表示函数没有入参,
输出表示函数的返回,
[]表示函数没有返回值,是void。

该题目给出的测试用例太过简单,
不方便思考,
下面使用5个整数演示思路:

解答思路1:
使用Java自带的Stack栈实现,
但是使用Stack的方式来做这道题,会造成速度较慢;
原因的话是Stack继承了Vector接口,
而Vector底层是一个Object[]数组,
空间扩容和移位的会增加 执行用时。

解答思路2:
使用LinkedList来做Stack的容器,
因为LinkedList实现了Deque接口,
所以Stack能做的事LinkedList都能做,
其本身结构是个双向链表,扩容消耗少。
但是不要像别人提交的执行时间超过100%的代码那样,
直接使用一个LinkedList当做队列,
那样确实是快,但是不符题意。

测试用例

package edu.yuwen.sowrd.num09.solution;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import edu.yuwen.sowrd.num09.sol2.CQueue;

public class CQueueTest {
    /**
     * 输入:
     * ["CQueue","appendTail","deleteHead","deleteHead"]
     * [[],[3],[],[]]
     * 输出:[null,null,3,-1]
     */
    @Test
    public void testCase1() {
        CQueue queue = new CQueue();
        queue.appendTail(3);

        int res = queue.deleteHead();
        Assertions.assertEquals(3, res);

        res = queue.deleteHead();
        Assertions.assertEquals(-1, res);
    }

    /**
     * 输入:
     * ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
     * [[],[],[5],[2],[],[]]
     * 输出:[null,-1,null,null,5,2]
     */
    @Test
    public void testCase2() {
        CQueue queue = new CQueue();

        int res = queue.deleteHead();
        Assertions.assertEquals(-1, res);

        queue.appendTail(5);
        queue.appendTail(2);

        res = queue.deleteHead();
        Assertions.assertEquals(5, res);

        res = queue.deleteHead();
        Assertions.assertEquals(2, res);
    }
}

解答1

package edu.yuwen.sowrd.num09.sol1;

import java.util.Stack;

/**
 * 解答1:使用Java的Stack栈
 *
 */
public class CQueue {
    Stack<Integer> tail;
    Stack<Integer> head;

    public CQueue() {
        tail = new Stack<>();
        head = new Stack<>();
    }

    public void appendTail(int value) {
        tail.push(value);
    }

    public int deleteHead() {
        // 第一次pop,
        Integer res = popOrNull(head);
        // 如果不为null,则返回结果
        if (res != null) {
            return res;
        }
        // 如果为null,则需要转移tail的数字到head
        transferTail2Head();

        // 第二次pop
        res = popOrNull(head);
        // 如果为null,则队列空,返回-1
        if (res == null) {
            return -1;
        }
        return res;
    }

    private void transferTail2Head() {
        Integer num = popOrNull(tail);
        while (num != null) {
            head.push(num);
            num = popOrNull(tail);
        }
    }

    /**
     * pop前先进行检查, 当栈为空时,返回null,而不是抛出异常
     */
    private Integer popOrNull(Stack<Integer> stack) {
        if (stack.isEmpty()) {
            return null;
        }
        return stack.pop();
    }
}

解答2 推荐

package edu.yuwen.sowrd.num09.sol2;

import java.util.Deque;
import java.util.LinkedList;

/**
 * 
 * 解法2:使用Deque来替代Stack,仅限使用Deque的两个方法模拟栈的后进先出
 *
 */
public class CQueue {
    // 使用Deque的addLast模拟栈的push
    // 使用Deque的pollLast模拟栈的pop,不使用removeLast的原因是队列为空时,会抛出异常
    Deque<Integer> tail;
    Deque<Integer> head;

    public CQueue() {
        // LinkedList实现了队列
        tail = new LinkedList<>();
        head = new LinkedList<>();
    }

    public void appendTail(int value) {
        tail.addLast(value);
    }

    public int deleteHead() {
        if (head.isEmpty()) {
            if (tail.isEmpty()) {
                // 确定队列空,返回-1
                return -1;
            }
            Integer num = tail.pollLast();
            while (num != null) {
                head.addLast(num);
                num = tail.pollLast();
            }
        }
        // 因为判断了tail不为空,队列至少有一个元素
        return head.pollLast();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值