leetcode
leetcode 751 ~ 800
设计循环双端队列

设计循环双端队列

难度:

标签:

题目描述

代码结果

运行时间: 47 ms, 内存: 17.2 MB


/*
 * This solution implements the MyCircularDeque class using an array to represent the deque.
 * The key is to maintain two pointers, front and rear, to track the positions where elements
 * are inserted or removed. We also keep track of the number of elements in the deque to check
 * for full and empty conditions.
 * Note: Java Streams are not particularly suitable for this problem, as it involves direct manipulation
 * of array indices and maintaining state, which is more straightforward with traditional loops and conditions.
 */

import java.util.stream.IntStream;

public class MyCircularDeque {
    private int[] deque;
    private int front;
    private int rear;
    private int size;
    private int capacity;

    public MyCircularDeque(int k) {
        capacity = k;
        deque = new int[k];
        front = 0;
        rear = -1;
        size = 0;
    }

    public boolean insertFront(int value) {
        if (isFull()) return false;
        front = (front - 1 + capacity) % capacity;
        deque[front] = value;
        size++;
        if (size == 1) rear = front;
        return true;
    }

    public boolean insertLast(int value) {
        if (isFull()) return false;
        rear = (rear + 1) % capacity;
        deque[rear] = value;
        size++;
        return true;
    }

    public boolean deleteFront() {
        if (isEmpty()) return false;
        front = (front + 1) % capacity;
        size--;
        return true;
    }

    public boolean deleteLast() {
        if (isEmpty()) return false;
        rear = (rear - 1 + capacity) % capacity;
        size--;
        return true;
    }

    public int getFront() {
        if (isEmpty()) return -1;
        return deque[front];
    }

    public int getRear() {
        if (isEmpty()) return -1;
        return deque[rear];
    }

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

    public boolean isFull() {
        return size == capacity;
    }
}

解释

方法:

该题解使用双向链表来实现循环双端队列。通过维护队列的头节点 _first 和尾节点 _last,可以在 O(1) 的时间复杂度内完成插入、删除、获取头尾元素等操作。同时使用 _len 变量记录队列的当前长度,方便判断队列是否为空或已满。

时间复杂度:

O(1)

空间复杂度:

O(k)

代码细节讲解

🦆
在初始化循环双端队列时,你是如何处理节点的前驱和后继关系以确保它们正确维护循环性质的?
在题解中提供的代码里,初始化一个循环双端队列并没有显式地设置节点的前驱和后继关系来维护循环性质,因为每当新节点被加入时,它的前驱和后继指针是根据队列的当前状态动态更新的。特别是当队列为空时,新插入的第一个节点的前驱和后继都指向自身,这在代码中没有直接体现,而是通过在队列为空时将_first和_last都指向新节点来隐式实现。
🦆
当从双端队列中删除元素导致队列为空时(即长度从1变为0),你有没有在代码中显式地清除节点的前驱和后继指针?如果没有,这会造成什么潜在的问题?
在题解中,当队列长度从1变为0时,代码确实将_first和_last指针都设置为None,从而使队列为空状态。但是,没有显式地清除被删除节点的前驱和后继指针。在大多数情况下,这不会造成问题,因为Python的垃圾回收机制会处理这些孤立的节点。然而,在某些环境或长时间运行的系统中,如果这些节点的引用未被清除,可能会导致内存泄漏。
🦆
在插入元素到队列头部和尾部时,如何处理前驱和后继指针的更新以确保队列的双向链表结构不会被破坏?
在向队列头部插入元素时,新节点的next指针指向原来的_first节点,然后更新原_first节点的prev指针指向新节点,并将_first更新为新节点。在向队列尾部插入时,新节点的prev指针指向原来的_last节点,然后更新原_last节点的next指向新节点,并将_last更新为新节点。这种方式确保了每次插入操作都正确维护了双向链表的结构,使得每个节点都正确地连接到其前驱和后继节点。
🦆
你提到了使用双向链表实现循环双端队列,但在代码实现中似乎没有看到循环的体现(如头尾相连)。这是否是一个遗漏,还是故意为之?如果是故意为之,请解释使用非循环双向链表的考虑。
这不是一个遗漏,而是一个设计选择。在题解中使用的是非循环的双向链表。这种选择简化了实现,特别是在处理队列头部和尾部的插入和删除操作时,不需要考虑复杂的循环条件(如头尾相连)。此外,非循环链表在逻辑上更直观,易于理解和维护。使用非循环链表的主要考虑是避免循环引用带来的复杂性,尤其是在自动内存管理的语言环境下,循环引用可能需要额外的垃圾回收处理。

相关问题

设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 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

 

提示:

  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。