返回

技术实践:打造完美的双端队列——LeetCode 641 深度解析

前端

在计算机科学领域,队列是一种常见的数据结构,它遵循先进先出(FIFO)的原则。与普通的队列不同,循环双端队列允许我们在队列的两端进行插入和删除操作,这使其更加灵活和高效。

要设计一个循环双端队列,我们需要使用两个指针来分别指向队头和队尾。当我们在队头插入一个元素时,我们将队头指针后移一位;当我们在队尾插入一个元素时,我们将队尾指针前移一位。当我们在队头删除一个元素时,我们将队头指针前移一位;当我们在队尾删除一个元素时,我们将队尾指针后移一位。

为了避免指针越界,我们可以使用一个数组来存储队列中的元素,并使用两个变量来记录队头和队尾的位置。当队头指针到达数组的末尾时,我们将它重置为数组的开头;当队尾指针到达数组的开头时,我们将它重置为数组的末尾。

class CircularDeque {
    private int[] elements;
    private int head;
    private int tail;
    private int size;

    public CircularDeque(int k) {
        elements = new int[k];
        head = 0;
        tail = 0;
        size = 0;
    }

    public boolean insertFront(int value) {
        if (isFull()) {
            return false;
        }

        head = (head - 1 + elements.length) % elements.length;
        elements[head] = value;
        size++;
        return true;
    }

    public boolean insertLast(int value) {
        if (isFull()) {
            return false;
        }

        elements[tail] = value;
        tail = (tail + 1) % elements.length;
        size++;
        return true;
    }

    public boolean deleteFront() {
        if (isEmpty()) {
            return false;
        }

        head = (head + 1) % elements.length;
        size--;
        return true;
    }

    public boolean deleteLast() {
        if (isEmpty()) {
            return false;
        }

        tail = (tail - 1 + elements.length) % elements.length;
        size--;
        return true;
    }

    public int getFront() {
        if (isEmpty()) {
            return -1;
        }

        return elements[head];
    }

    public int getRear() {
        if (isEmpty()) {
            return -1;
        }

        return elements[(tail - 1 + elements.length) % elements.length];
    }

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

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

通过 LeetCode 641 题的练习,我们可以巩固我们对循环双端队列的理解。在这道题中,我们需要设计一个循环双端队列,并实现以下操作:

  • pushFront(value):将一个元素插入到队列的前面。
  • pushBack(value):将一个元素插入到队列的后面。
  • popFront():从队列的前面删除一个元素。
  • popBack():从队列的后面删除一个元素。
  • front():返回队列前面的元素。
  • back():返回队列后面的元素。
  • empty():判断队列是否为空。

为了解决这道题,我们可以使用上面介绍的循环双端队列的实现。我们可以使用一个数组来存储队列中的元素,并使用两个变量来记录队头和队尾的位置。当我们在队头插入一个元素时,我们将队头指针后移一位;当我们在队尾插入一个元素时,我们将队尾指针前移一位。当我们在队头删除一个元素时,我们将队头指针前移一位;当我们在队尾删除一个元素时,我们将队尾指针后移一位。

class Solution {
    /**
     * Initialize your data structure here. Set the size of the deque to be k.
     */
    public MyCircularDeque(int k) {
        elements = new int[k];
        head = 0;
        tail = 0;
        size = 0;
    }

    /**
     * Adds an item at the front of Deque. Return true if the operation is successful.
     */
    public boolean insertFront(int value) {
        if (isFull()) {
            return false;
        }

        head = (head - 1 + elements.length) % elements.length;
        elements[head] = value;
        size++;
        return true;
    }

    /**
     * Adds an item at the rear of Deque. Return true if the operation is successful.
     */
    public boolean insertLast(int value) {
        if (isFull()) {
            return false;
        }

        elements[tail] = value;
        tail = (tail + 1) % elements.length;
        size++;
        return true;
    }

    /**
     * Deletes an item from the front of Deque. Return true if the operation is successful.
     */
    public boolean deleteFront() {
        if (isEmpty()) {
            return false;
        }

        head = (head + 1) % elements.length;
        size--;
        return true;
    }

    /**
     * Deletes an item from the rear of Deque. Return true if the operation is successful.
     */
    public boolean deleteLast() {
        if (isEmpty()) {
            return false;
        }

        tail = (tail - 1 + elements.length) % elements.length;
        size--;
        return true;
    }

    /**
     * Get the front item from the deque.
     */
    public int getFront() {
        if (isEmpty()) {
            return -1;
        }

        return elements[head];
    }

    /**
     * Get the last item from the deque.
     */
    public int getRear() {
        if (isEmpty()) {
            return -1;
        }

        return elements[(tail - 1 + elements.length) % elements.length];
    }

    /**
     * Checks whether the circular deque is empty or not.
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Checks whether the circular deque is full or not.
     */
    public boolean isFull() {
        return size == elements.length;
    }

    private int[] elements;
    private int head;
    private int tail;
    private int size;
}

通过对循环双端队列的学习和 LeetCode 641 题的练习,我们加深了对数据结构和算法的理解。希望这篇文章能够帮助您在计算机科学的道路上更进一步。