用JavaScript刷leetcode第703题-设计循环队列

492 阅读3分钟

一、前置知识

1.1 队列

队列是一种操作受限制的线性表,其特点是先进先出,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作

1.2 队列缺点

不能利用有效空间,执行删除操作后,会清理一些内存空间出来,但是,由于只能在队尾插入,故前面清理出的空间就不能有效利用了。
但是环形队列可以解决这个问题,把队列空间想象成一个环形空间,环形空间中的存储单元循环使用。

1.3 环形队列

无论插入或删除操作,一旦rear指针增1或者front指针增1超出了所分配的队列空间,就让它指向这篇连续空间的起始位置。
环形链表又被称为环形缓冲器。

二、题目描述

看完基础知识,我们来看下题目描述,具体需要实现什么:

  • MyCircularQueue(k): 构造器,设置队列长度为 k
  • Front: 从队首获取元素。如果队列为空,返回 -1
  • Rear: 获取队尾元素。如果队列为空,返回 -1
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真
  • isEmpty(): 检查循环队列是否为空
  • isFull(): 检查循环队列是否已满 若想要看更详细的操作,请看leetcode题目链接

三、解题

3.1 具体实现

3.1.1 构造器,设置队列长度为 k

用来创建环形队列实例,环形队列需创建时知道 队列,front指针,rear指针,队列最大容量。

var MyCircularQueue = function (k) {
    this.front = 0
    this.rear = 0
    this.max = k
    this.queue = new Array(k).fill(null)
}

3.1.2 检查队列是否为空

判空的条件很简单,其实就是front、rear指针指向同一元素,该元素为null

MyCircularQueue.prototype.isEmpty = function () {
    return (this.front === this.rear) && (this.queue[this.front] === null)
}

3.1.3 检查循环队列是否已满

判空的条件很简单,其实就是front、rear指针指向同一元素,该元素不为null

MyCircularQueue.prototype.isEmpty = function () {
    return (this.front === this.rear) && (this.queue[this.front] !== null)
}

3.1.4 从队首获取元素。如果队列为空,返回 -1

先判空,判空则返回-1

MyCircularQueue.prototype.Front = function () {
    if(this.isEmpty()) return -1
    
    return this.queue[this.front]
}

3.1.5 获取队尾元素。如果队列为空,返回 -1

先判空,判空则返回-1。这里rear需要注意,这个指针队列尾元素的后一位

MyCircularQueue.prototype.Rear = function () {
    if(this.isEmpty()) return -1
    
    return this.queue[this.rear === 0 ? this.max - 1 : this.rear - 1 ]
}

3.1.6 向循环队列插入一个元素。如果成功插入则返回真

注意指针后移时取余

MyCircularQueue.prototype.enQueue = function(value) {
  // 判满返回false
  if(this.isFull()) return false

  // 先往队尾添加
  this.queue[this.rear] = value
  // 尾指针后移: 这个环有点像取余,比如队列长7,尾指针到了队尾,再加就是 (7+1) % 7
  this.rear = (this.rear + 1) % this.max

  return true
};

3.1.7 从循环队列中删除一个元素。如果成功删除则返回真

注意指针后移时取余

MyCircularQueue.prototype.deQueue = function() {
  // 判空返回false
  if(this.isEmpty()) return false

  // 队头出队
  this.queue[this.front] = null
  // 头指针后移
  this.front = (this.front + 1) % this.max

  return true
};

3.2 整体代码

git代码地址

/**
 * @param {number} k
 */
 var MyCircularQueue = function(k) {
  // 头指针
  this.front = 0
  // 尾指针
  this.rear = 0
  // 队列长度
  this.max = k
  // 队列
  this.queue = Array(k).fill(null)
};

/** 
 * @param {number} value
 * @return {boolean}
 */
MyCircularQueue.prototype.enQueue = function(value) {
  // 判满返回false
  if(this.isFull()) return false

  // 先往队尾添加
  this.queue[this.rear] = value
  // 尾指针后移: 这个环有点像取余,比如队列长7,尾指针到了队尾,再加就是 (7+1) % 7
  this.rear = (this.rear + 1) % this.max

  return true
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.deQueue = function() {
  // 判空返回false
  if(this.isEmpty()) return false

  // 队头出队
  this.queue[this.front] = null
  // 头指针后移
  this.front = (this.front + 1) % this.max

  return true
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Front = function() {
  // 队列为空,返回-1
  if(this.isEmpty()) return -1

  return this.queue[this.front]
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Rear = function() {
  // 队列为空,返回-1
  if(this.isEmpty()) return -1

  return this.queue[this.rear === 0 ? this.max -1 : this.rear - 1]
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isEmpty = function() {
  // 头指针、尾指针同时指向一个元素,且该元素为null
  return (this.front === this.rear) && (this.queue[this.front] === null)
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isFull = function() {
  // 头指针、尾指针同时指向一个元素,且该元素不为null
  return (this.front === this.rear) && (this.queue[this.front] !== null)
};