LeetCode 每日一题——622. 设计循环队列

1.题目描述

622. 设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

2.解题思路与代码

2.1 解题思路

这道题就是需要写一个双端队列,并且按照题目要求需要提供六个对外的方法,分别是获取头元素(Front)、获取尾元素(Rear)、入队(enQueue)、出队(deQueue)、对列是否为空(isEmpty)、对列是否已满(isFull)。既然是双端对列首先就会考虑到需要头尾两个变量来指向队列的队头和队尾,那么在初始化的时候就会使用 head 和 rear 两个变量,如果使用这两个变量指向头尾的话会让整个代码变得复杂,而且很容易把自己绕晕,比如在计算队列大小的时候。
我们可以看到队尾变量其实只有在入队和获取队尾元素的时候才会使用到,那么我们就可以不需要使用队尾变量,而是使用一个 size 变量来记录当前队列的大小,如果需要队尾的时候就使用 head 的位置加上队列长度 size 来确定队尾的位置。确定队尾位置就会出现两种情况:head+size 小于初始队列长度和 head+size 大于等于队列长度,处理方式如下:

  • head+size 小于初始队列长度:此时直接队尾就是 head+size
  • head+size 大于等于队列长度:此时队尾位置超出数组长度,那么队尾的位置就需要回到数组第一位开始往下数,即( head+size)% queue.length

通过上面的设定,题目规定需要实现的及方法就变得非常简单了:

  1. 获取头元素(Front):直接返回 head 位置元素
  2. 获取尾元素(Rear):根据上面提到的获取队尾元素位置的方法,返回即可
  3. 入队(enQueue):同样先获取到队尾位置,然后在队尾位置上插入新的元素
  4. 出队(deQueue):直接让 head 加一向后移动一位,此时队头就从新的位置开始,原来位置上的元素不动,入队时直接覆盖即可。需要注意如果 head 自增后等于数组长度,那么就需要回到头,从 0 位置开始
  5. 对列是否为空(isEmpty):因为我们维护了一个 size 变量记录队列中的元素,因此直接返回 size 是否为 0 就可以了不再需要复杂的计算
  6. 对列是否已满(isFull):同理判断 size 是否等于数组长度即可

2.2 代码

class MyCircularQueue {


    int[] queue;
    int head;
    int size;

    public MyCircularQueue(int k) {
        queue = new int[k];
        head = 0;
        size = 0;
    }

    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        int rear = head + size;

        int index = rear >= queue.length ? rear % queue.length : rear;
        queue[index] = value;
        size++;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        head = head + 1 == queue.length ? 0 : head + 1;
        size--;
        return true;
    }

    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return queue[head];
    }

    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        int rear = head + size;
        int index = rear > queue.length ? rear % queue.length : rear;
        return queue[index - 1];
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isFull() {
        return size == queue.length;
    }
}

2.3 测试结果

通过测试

测试结果

3.总结

  • 维护 size 变量记录队列长度可以简化很多代码
  • 注意队尾和队头的边界
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值