力扣每日一题(难的我也不会)622. 设计循环队列(2022.8.2)

本文探讨了如何设计和实现一个循环队列,包括使用链表和虚拟头结点的方法,以及enQueue和deQueue操作。虽然最初的实现只击败了9.47%的用户,但通过对比官方的数组双指针解决方案,了解到链表实现的效率问题。循环队列作为一种线性数据结构,其FIFO特性在数据处理中有着广泛应用。
摘要由CSDN通过智能技术生成

622. 设计循环队列

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

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

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

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

对于栈,队列,链表,哈希表这类设计题型,我们需要构造出Node节点去存储相应的值

在链表类题型中,根据链表存储类型可构造以下节点

    class Node {

        int val;
        Node next;

        public Node() {}

        public Node(int val) {
            this.val = val;
        }
    }

因为只需要存储值和next指针,我们只需构造出只有值和指针的Node类即可

在哈希表中,因为哈希表是根据数组加链表实现的,链表中不仅要存储key值,还需要存储对应的val值,所以我们需要三个属性,key,val,next指针,哈希表中key值不能更改,所以我们使用setter,getter来对key以及val赋值

    class Node {

        private int key;
        private int val;
        Node next;

        Node() {
        }

        Node(int key, int val) {
            this.key = key;
            this.val = val;
        }

        public int getKey() {
            return key;
        }

        public int getVal() {
            return val;
        }

        public void setVal(int val) {
            this.val = val;
        }
    }

根据题意,我们需要有队列最大长度k,队列当前长度size,虚拟头结点head,使用虚拟头结点记录队列的初始节点。

在本题中,我们主要需要实现的时enQueue(val)以及deQueue(),其他四个方法很容易就可以实现

根据队列特性,插入应插入到队列尾部,弹出应弹出队列头部的Node节点,代码如下,会在代码中解释

    public boolean enQueue(int value) {
        if (size == k) return false; // 如果队列已满,返回插入失败
        Node node;    // 定义初始节点,如果队列中没有值直接添加,下面那个while不会走,如果有值,找到尾结点
        if (head.next == null) {
            node = head;
        } else {
            node = head.next;
        }
        while (node.next != head.next) {  // 如果当前节点的下一个是头结点,那么当前节点就是尾结点,在当前节点后面添加新节点
            node = node.next;
        }
        Node insert = new Node(value);
        node.next = insert;
        insert.next = head.next;
        size++; // 队列长度加1
        return true;
    }

    public boolean deQueue() {
        if (size == 0) return false; // 如果队列为空,返回删除失败
        if (head.next.next == head.next) { // 判断是否只有一个节点,如果只有一个节点,直接让虚拟头结点指向null,这里需要特判下,我还没有想出不需要特判的解法,如果哪位小伙伴知道,可以私信我
            head.next = null;
        } else { // 找到队列尾节点,让尾节点指向头结点的下一个节点,之后改变虚拟头结点指向,在Java中这样就达到了删除的效果
            Node node = head.next;
            while (node.next != head.next) {
                node = node.next;
            }
            node.next = node.next.next;
            head.next = node.next;
        }
        size--; // 队列长度减1
        return true;
    }

整体代码

class MyCircularQueue {

    class Node {
        int val;
        Node next;

        public Node() {
        }

        public Node(int val) {
            this.val = val;
        }

        @Override
        public String toString() {
            return String.valueOf(val);
        }
    }

    Node head;
    int k;
    int size;

    public MyCircularQueue(int k) {
        this.k = k;
        size = 0;
        head = new Node();
    }

    public boolean enQueue(int value) {
        if (size == k) return false;
        Node node;
        if (head.next == null) {
            node = head;
        } else {
            node = head.next;
        }
        while (node.next != head.next) {
            node = node.next;
        }
        Node insert = new Node(value);
        node.next = insert;
        insert.next = head.next;
        size++;
        return true;
    }

    public boolean deQueue() {
        if (size == 0) return false;
        if (head.next.next == head.next) {
            head.next = null;
        } else {
            Node node = head.next;
            while (node.next != head.next) {
                node = node.next;
            }
            node.next = node.next.next;
            head.next = node.next;
        }
        size--;
        return true;
    }

    public int Front() {
        return head.next == null ? -1 : head.next.val;
    }

    public int Rear() {
        if (size == 0) return -1;
        Node node = head.next;
        while (node.next != head.next) {
            node = node.next;
        }
        return node.val;
    }

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

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

}

然后我发现只击败了9.47%的用户,感觉咋都不至于这么低,就去看了下题解

在题解中官方是使用数组+双指针构建的循环队列,所以效率特别快

受队列是特殊的链表影响,所以开始就没想到用数组去解,而是用链表的方式去解

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值