一、前言
这题需要一些前置知识,可以先看我的上篇文章 设计循环队列
循环双端队列与普通循环队列的主要区别就是
- 循环双端队列既可以在队首插入删除,也可以在队尾插入删除,不遵循先进先出。
- 而普通循环队列只能在队尾插入,队首删除,还是遵循先进先出的。 搞清楚这些后,我将用数组模拟实循环双端队列
二、题目描述:
设计实现双端队列。
你的实现需要支持以下操作:
- MyCircularDeque(k):构造函数,双端队列的大小为k。
- insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。
- insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。
- deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。
- deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。
- getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。
- getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。
- isEmpty():检查双端队列是否为空。
- isFull():检查双端队列是否满了。
示例:
MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3
circularDeque.insertLast(1); // 返回 true
circularDeque.insertLast(2); // 返回 true
circularDeque.insertFront(3); // 返回 true
circularDeque.insertFront(4); // 已经满了,返回 false
circularDeque.getRear(); // 返回 2
circularDeque.isFull(); // 返回 true
circularDeque.deleteLast(); // 返回 true
circularDeque.insertFront(4); // 返回 true
circularDeque.getFront(); // 返回 4
更加详细的描述请看: leetcode连接
三、解题
如果你之前设计过循环队列,这题其实很简单。接下来我将带你逐一实现双端队列需要支持的操作
3.1 MyCircularDeque(k):构造函数,双端队列的大小为k
用数组模拟循环双端队列申请下来的空间,需要两个指针来模拟队列的头尾,还需要一个变量记录空间的最大容量
/**
* @param {number} k
*/
var MyCircularDeque = function(k) {
// 队列申请到空间的最大容量
this.max = k
// 头
this.front = 0
// 尾的后一位, 设计的是这种[front, rear)
this.rear = 0
// 队列申请到的空间
this.queue = new Array(k).fill(null)
}
3.2 insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true
- 插入操作首先要考虑队列是否满了
- 队首插入,要考虑两种情况:1、队尾 2、非队尾
- 非队尾很简单this.front = this.front - 1
- 队尾 this.front = this.max - 1
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertFront = function(value) {
// 如果队列满了,插入失败
if(this.isFull()) return false
// 否则front指针向前移动一位,但是要考虑front 在 0 的位置时
this.front = this.front === 0 ? this.max - 1 : this.front - 1
// 插入
this.queue[this.front] = value
// 插入成功
return true
};
3.3 insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true
- 先判满
- 队尾插入,要考虑两种情况:1、队尾 2、非队尾
- 两种情况可以分开写,也可一行代码搞定分开写的代码,我注释了
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertLast = function(value) {
// 如果队列满了,插入失败
if(this.isFull()) return false
// 插入
this.queue[this.rear] = value
// 后移
// this.rear = this.rear === this.max - 1 ? 0 : this.rear + 1
this.rear = (this.rear + 1) % this.max
// 插入成功
return true
};
3.4 deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true
- 先判空,判空则删除失败
- 队头删除,要考虑两种情况:1、队尾 2、非队尾
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteFront = function() {
// 判空,删除失败
if(this.isEmpty()) return false
// 删除
this.queue[this.front] = null
// 指针后移
this.front = (this.front + 1) % this.max
// 删除成功
return true
};
3.5 deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true
- 先判空,判空则删除失败
- 队头删除,要考虑两种情况:1、队尾 2、非队尾
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteLast = function() {
// 判空,删除失败
if(this.isEmpty()) return false
// 指针后移
this.rear = this.rear === 0 ? this.max - 1 : this.rear - 1
// 删除
this.queue[this.rear] = null
// 删除成功
return true
};
3.6 getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1
- 判空,则返回-1
- 返回第一个元素
/**
* @return {number}
*/
MyCircularDeque.prototype.getFront = function() {
// 判空
if(this.isEmpty()) return -1
// 返回
return this.queue[this.front]
};
3.7 getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1
- 判空,则返回-1
- 返回最后一个元素
- 注意rear指向的是 尾 的 前一位
/**
* @return {number}
*/
MyCircularDeque.prototype.getRear = function() {
// 判空
if(this.isEmpty()) return -1
// rear 指的是 尾的前一位, 当指向0 时实际指向尾
return this.queue[this.rear === 0 ? this.max - 1 : this.rear -1]
};
3.8 isEmpty():检查双端队列是否为空
- 判空的条件是:front 和 rear 指向同一个位置,并且此位置上的元素是 null
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isEmpty = function() {
// front 和 rear 指向同一个位置,并且此位置上的元素是 null
return (this.front === this.rear) && (this.queue[this.front] === null)
};
3.9 isFull():检查双端队列是否满了
- 判满的条件是:front 和 rear 指向同一个位置,并且此位置上的元素不是 null
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isFull = function() {
// front 和 rear 指向同一个位置,并且此位置上的元素不是 null
return (this.front === this.rear) && (this.queue[this.front] !== null)
};
3.10 完整代码
/**
* 题号:641
* 题目地址:https://leetcode-cn.com/problems/design-circular-deque/
*/
/**
* @param {number} k
*/
var MyCircularDeque = function(k) {
// 队列申请到空间的最大容量
this.max = k
// 头
this.front = 0
// 尾的后一位, 设计的是这种[front, rear)
this.rear = 0
// 队列申请到的空间
this.queue = new Array(k).fill(null)
}
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertFront = function(value) {
// 如果队列满了,插入失败
if(this.isFull()) return false
// 否则front指针向前移动一位,但是要考虑front 在 0 的位置时
this.front = this.front === 0 ? this.max - 1 : this.front - 1
// 插入
this.queue[this.front] = value
// 插入成功
return true
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertLast = function(value) {
// 如果队列满了,插入失败
if(this.isFull()) return false
// 插入
this.queue[this.rear] = value
// 后移
// this.rear = this.rear === this.max - 1 ? 0 : this.rear + 1
this.rear = (this.rear + 1) % this.max
// 插入成功
return true
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteFront = function() {
// 判空,删除失败
if(this.isEmpty()) return false
// 删除
this.queue[this.front] = null
// 指针后移
this.front = (this.front + 1) % this.max
// 删除成功
return true
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteLast = function() {
// 判空,删除失败
if(this.isEmpty()) return false
// 指针后移
this.rear = this.rear === 0 ? this.max - 1 : this.rear - 1
// 删除
this.queue[this.rear] = null
// 删除成功
return true
};
/**
* @return {number}
*/
MyCircularDeque.prototype.getFront = function() {
// 判空
if(this.isEmpty()) return -1
// 返回
return this.queue[this.front]
};
/**
* @return {number}
*/
MyCircularDeque.prototype.getRear = function() {
// 判空
if(this.isEmpty()) return -1
// rear 指的是 尾的前一位, 当指向0 时实际指向尾
return this.queue[this.rear === 0 ? this.max - 1 : this.rear -1]
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isEmpty = function() {
// front 和 rear 指向同一个位置,并且此位置上的元素是 null
return (this.front === this.rear) && (this.queue[this.front] === null)
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isFull = function() {
// front 和 rear 指向同一个位置,并且此位置上的元素不是 null
return (this.front === this.rear) && (this.queue[this.front] !== null)
};
/**
* Your MyCircularDeque object will be instantiated and called as such:
* var obj = new MyCircularDeque(k)
* var param_1 = obj.insertFront(value)
* var param_2 = obj.insertLast(value)
* var param_3 = obj.deleteFront()
* var param_4 = obj.deleteLast()
* var param_5 = obj.getFront()
* var param_6 = obj.getRear()
* var param_7 = obj.isEmpty()
* var param_8 = obj.isFull()
*/