diff --git a/solution/1600-1699/1670.Design Front Middle Back Queue/README.md b/solution/1600-1699/1670.Design Front Middle Back Queue/README.md index 96e1ea7629d67..5e9a9da09aac5 100644 --- a/solution/1600-1699/1670.Design Front Middle Back Queue/README.md +++ b/solution/1600-1699/1670.Design Front Middle Back Queue/README.md @@ -64,11 +64,19 @@ q.popFront(); // 返回 -1 -> [] (队列为空) -**方法一:双“双端队列”** +**方法一:两个双端队列** -我们用两个双端队列,其中 $q_1$ 存储前半部分,而 $q_2$ 存储后半部分。每次由 `rebalance` 函数来维护两个队列的平衡性,即保持 $q_1$ 和 $q_2$ 的长度差不超过 $1$ 且 $q_2$ 的长度不小于 $q_1$ 的长度。 +我们用两个双端队列,其中 $q_1$ 存储前半部分,而 $q_2$ 存储后半部分。每次由 `rebalance` 函数来维护两个队列的平衡性,即保持 $q_2$ 的长度大于等于 $q_1$ 的长度,且长度之差不超过 $1$。 -时间复杂度方面,每次操作的时间复杂度为 $O(1)$,总的空间复杂度为 $O(n)$。 +在 `pushFront`、`pushMiddle` 和 `pushBack` 函数中,我们只需要将元素添加到 $q_1$ 或 $q_2$ 中,并调用 `rebalance` 函数即可。 + +对于 `popFront` 函数,我们需要判断 $q_1$ 和 $q_2$ 是否为空,如果都为空,则返回 $-1$,否则我们需要判断 $q_1$ 是否为空,如果不为空,则弹出 $q_1$ 的队首元素,否则弹出 $q_2$ 的队首元素,并调用 `rebalance` 函数。 + +对于 `popMiddle` 函数,我们需要判断 $q_1$ 和 $q_2$ 是否为空,如果都为空,则返回 $-1$,否则我们需要判断 $q_1$ 和 $q_2$ 的长度是否相等,如果相等,则弹出 $q_1$ 的队尾元素,否则弹出 $q_2$ 的队首元素,并调用 `rebalance` 函数。 + +对于 `popBack` 函数,我们只需要判断 $q_2$ 是否为空,如果为空,则返回 $-1$,否则弹出 $q_2$ 的队尾元素,并调用 `rebalance` 函数。 + +以上操作的时间复杂度均为 $O(1)$,空间复杂度为 $O(n)$,其中 $n$ 是队列中的元素数量。 @@ -304,134 +312,467 @@ private: ### **Go** ```go -type FrontMiddleBackQueue struct{} +type FrontMiddleBackQueue struct { + q1, q2 Deque +} -var a []int +func Constructor() FrontMiddleBackQueue { + return FrontMiddleBackQueue{} +} -func Constructor() (_ FrontMiddleBackQueue) { - a = nil - return +func (this *FrontMiddleBackQueue) PushFront(val int) { + this.q1.PushFront(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushFront(v int) { - a = append([]int{v}, a...) +func (this *FrontMiddleBackQueue) PushMiddle(val int) { + this.q1.PushBack(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushMiddle(v int) { - p := len(a) / 2 - a = append(a[:p], append([]int{v}, a[p:]...)...) +func (this *FrontMiddleBackQueue) PushBack(val int) { + this.q2.PushBack(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushBack(v int) { - a = append(a, v) +func (this *FrontMiddleBackQueue) PopFront() int { + if this.q1.Empty() && this.q2.Empty() { + return -1 + } + var val int + if !this.q1.Empty() { + val = this.q1.PopFront() + } else { + val = this.q2.PopFront() + } + this.rebalance() + return val } -func (FrontMiddleBackQueue) PopFront() (ans int) { - if len(a) == 0 { +func (this *FrontMiddleBackQueue) PopMiddle() int { + if this.q1.Empty() && this.q2.Empty() { return -1 } - ans = a[0] - a = a[1:] - return + var val int + if this.q1.Size() == this.q2.Size() { + val = this.q1.PopBack() + } else { + val = this.q2.PopFront() + } + this.rebalance() + return val } -func (FrontMiddleBackQueue) PopMiddle() (ans int) { - if len(a) == 0 { +func (this *FrontMiddleBackQueue) PopBack() int { + if this.q2.Empty() { return -1 } - p := (len(a) - 1) / 2 - ans = a[p] - a = append(a[:p], a[p+1:]...) + val := this.q2.PopBack() + this.rebalance() + return val +} + +func (this *FrontMiddleBackQueue) rebalance() { + if this.q1.Size() > this.q2.Size() { + this.q2.PushFront(this.q1.PopBack()) + } + if this.q2.Size() > this.q1.Size()+1 { + this.q1.PushBack(this.q2.PopFront()) + } +} + +// template +type Deque struct{ l, r []int } + +func (q Deque) Empty() bool { + return len(q.l) == 0 && len(q.r) == 0 +} + +func (q Deque) Size() int { + return len(q.l) + len(q.r) +} + +func (q *Deque) PushFront(v int) { + q.l = append(q.l, v) +} + +func (q *Deque) PushBack(v int) { + q.r = append(q.r, v) +} + +func (q *Deque) PopFront() (v int) { + if len(q.l) > 0 { + q.l, v = q.l[:len(q.l)-1], q.l[len(q.l)-1] + } else { + v, q.r = q.r[0], q.r[1:] + } return } -func (FrontMiddleBackQueue) PopBack() (ans int) { - if len(a) == 0 { - return -1 +func (q *Deque) PopBack() (v int) { + if len(q.r) > 0 { + q.r, v = q.r[:len(q.r)-1], q.r[len(q.r)-1] + } else { + v, q.l = q.l[0], q.l[1:] } - ans = a[len(a)-1] - a = a[:len(a)-1] return } -``` -### **JavaScript** +func (q Deque) Front() int { + if len(q.l) > 0 { + return q.l[len(q.l)-1] + } + return q.r[0] +} -```js -var FrontMiddleBackQueue = function () { - this.left = []; - this.right = []; -}; +func (q Deque) Back() int { + if len(q.r) > 0 { + return q.r[len(q.r)-1] + } + return q.l[0] +} -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushFront = function (val) { - this.left.unshift(val); - this.rebalance(); -}; +func (q Deque) Get(i int) int { + if i < len(q.l) { + return q.l[len(q.l)-1-i] + } + return q.r[i-len(q.l)] +} /** - * @param {number} val - * @return {void} + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * obj := Constructor(); + * obj.PushFront(val); + * obj.PushMiddle(val); + * obj.PushBack(val); + * param_4 := obj.PopFront(); + * param_5 := obj.PopMiddle(); + * param_6 := obj.PopBack(); */ -FrontMiddleBackQueue.prototype.pushMiddle = function (val) { - this.left.push(val); - this.rebalance(); -}; +``` -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushBack = function (val) { - this.right.push(val); - this.rebalance(); -}; +### **TypeScript** -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popFront = function () { - if (this.isEmpty()) return -1; - let num = this.left.length == 0 ? this.right.shift() : this.left.shift(); - this.rebalance(); - return num; -}; +```ts +class FrontMiddleBackQueue { + private q1: Deque; + private q2: Deque; -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popMiddle = function () { - if (this.isEmpty()) return -1; - let num = this.left.length == this.right.length ? this.left.pop() : this.right.shift(); - this.rebalance(); - return num; -}; + constructor() { + this.q1 = new Deque(); + this.q2 = new Deque(); + } + + pushFront(val: number): void { + this.q1.pushFront(val); + this.rebalance(); + } + + pushMiddle(val: number): void { + this.q1.pushBack(val); + this.rebalance(); + } + + pushBack(val: number): void { + this.q2.pushBack(val); + this.rebalance(); + } + + popFront(): number { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = this.q1.isEmpty() ? this.q2.popFront() : this.q1.popFront(); + this.rebalance(); + return val!; + } + + popMiddle(): number { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = + this.q1.getSize() === this.q2.getSize() ? this.q1.popBack() : this.q2.popFront(); + this.rebalance(); + return val!; + } + + popBack(): number { + if (this.q2.isEmpty()) { + return -1; + } + const val = this.q2.popBack(); + this.rebalance(); + return val!; + } + + private rebalance(): void { + if (this.q1.getSize() > this.q2.getSize()) { + this.q2.pushFront(this.q1.popBack()!); + } + if (this.q2.getSize() > this.q1.getSize() + 1) { + this.q1.pushBack(this.q2.popFront()!); + } + } +} + +class Node { + value: T; + next: Node | null; + prev: Node | null; + + constructor(value: T) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + private front: Node | null; + private back: Node | null; + private size: number; + + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front!.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back!.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.front!.value; + this.front = this.front!.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.back!.value; + this.back = this.back!.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue(): T | undefined { + return this.front?.value; + } + + backValue(): T | undefined { + return this.back?.value; + } + + getSize(): number { + return this.size; + } + + isEmpty(): boolean { + return this.size === 0; + } +} /** - * @return {number} + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * var obj = new FrontMiddleBackQueue() + * obj.pushFront(val) + * obj.pushMiddle(val) + * obj.pushBack(val) + * var param_4 = obj.popFront() + * var param_5 = obj.popMiddle() + * var param_6 = obj.popBack() */ -FrontMiddleBackQueue.prototype.popBack = function () { - if (this.isEmpty()) return -1; - let num = this.right.pop(); - this.rebalance(); - return num; -}; +``` -FrontMiddleBackQueue.prototype.rebalance = function () { - while (this.left.length > this.right.length) { - this.right.unshift(this.left.pop()); +### **JavaScript** + +```js +class FrontMiddleBackQueue { + constructor() { + this.q1 = new Deque(); + this.q2 = new Deque(); } - while (this.right.length > this.left.length + 1) { - this.left.push(this.right.shift()); + + pushFront(val) { + this.q1.pushFront(val); + this.rebalance(); } -}; -FrontMiddleBackQueue.prototype.isEmpty = function () { - return this.left.length == 0 && this.right.length == 0; -}; + pushMiddle(val) { + this.q1.pushBack(val); + this.rebalance(); + } + + pushBack(val) { + this.q2.pushBack(val); + this.rebalance(); + } + + popFront() { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = this.q1.isEmpty() ? this.q2.popFront() : this.q1.popFront(); + this.rebalance(); + return val !== undefined ? val : -1; + } + + popMiddle() { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = + this.q1.getSize() === this.q2.getSize() ? this.q1.popBack() : this.q2.popFront(); + this.rebalance(); + return val !== undefined ? val : -1; + } + + popBack() { + if (this.q2.isEmpty()) { + return -1; + } + const val = this.q2.popBack(); + this.rebalance(); + return val !== undefined ? val : -1; + } + + rebalance() { + if (this.q1.getSize() > this.q2.getSize()) { + this.q2.pushFront(this.q1.popBack()); + } + if (this.q2.getSize() > this.q1.getSize() + 1) { + this.q1.pushBack(this.q2.popFront()); + } + } +} + +class Node { + constructor(value) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val) { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val) { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront() { + if (this.isEmpty()) { + return undefined; + } + const value = this.front.value; + this.front = this.front.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack() { + if (this.isEmpty()) { + return undefined; + } + const value = this.back.value; + this.back = this.back.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue() { + return this.front?.value; + } + + backValue() { + return this.back?.value; + } + + getSize() { + return this.size; + } + + isEmpty() { + return this.size === 0; + } +} /** * Your FrontMiddleBackQueue object will be instantiated and called as such: diff --git a/solution/1600-1699/1670.Design Front Middle Back Queue/README_EN.md b/solution/1600-1699/1670.Design Front Middle Back Queue/README_EN.md index 352be665fda78..29233c1f9a2bc 100644 --- a/solution/1600-1699/1670.Design Front Middle Back Queue/README_EN.md +++ b/solution/1600-1699/1670.Design Front Middle Back Queue/README_EN.md @@ -58,6 +58,20 @@ q.popFront(); // return -1 -> [] (The queue is empty) ## Solutions +**Solution 1: Two Deques** + +We use two deques, where $q_1$ stores the first half, and $q_2$ stores the second half. The `rebalance` function is used to maintain the balance between the two queues, i.e., keeping the length of $q_2$ greater than or equal to the length of $q_1$, and the difference in length does not exceed $1$. + +In the `pushFront`, `pushMiddle`, and `pushBack` functions, we only need to add elements to $q_1$ or $q_2$, and call the `rebalance` function. + +For the `popFront` function, we need to check whether $q_1$ and $q_2$ are empty. If both are empty, return $-1$. Otherwise, we need to check whether $q_1$ is empty. If not, pop the front element of $q_1$, otherwise pop the front element of $q_2$, and call the `rebalance` function. + +For the `popMiddle` function, we need to check whether $q_1$ and $q_2$ are empty. If both are empty, return $-1$. Otherwise, we need to check whether the lengths of $q_1$ and $q_2$ are equal. If they are equal, pop the last element of $q_1$, otherwise pop the front element of $q_2$, and call the `rebalance` function. + +For the `popBack` function, we only need to check whether $q_2$ is empty. If it is empty, return $-1$. Otherwise, pop the last element of $q_2$, and call the `rebalance` function. + +The time complexity of the above operations is $O(1)$, and the space complexity is $O(n)$, where $n$ is the number of elements in the queue. + ### **Python3** @@ -288,134 +302,467 @@ private: ### **Go** ```go -type FrontMiddleBackQueue struct{} +type FrontMiddleBackQueue struct { + q1, q2 Deque +} -var a []int +func Constructor() FrontMiddleBackQueue { + return FrontMiddleBackQueue{} +} -func Constructor() (_ FrontMiddleBackQueue) { - a = nil - return +func (this *FrontMiddleBackQueue) PushFront(val int) { + this.q1.PushFront(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushFront(v int) { - a = append([]int{v}, a...) +func (this *FrontMiddleBackQueue) PushMiddle(val int) { + this.q1.PushBack(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushMiddle(v int) { - p := len(a) / 2 - a = append(a[:p], append([]int{v}, a[p:]...)...) +func (this *FrontMiddleBackQueue) PushBack(val int) { + this.q2.PushBack(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushBack(v int) { - a = append(a, v) +func (this *FrontMiddleBackQueue) PopFront() int { + if this.q1.Empty() && this.q2.Empty() { + return -1 + } + var val int + if !this.q1.Empty() { + val = this.q1.PopFront() + } else { + val = this.q2.PopFront() + } + this.rebalance() + return val } -func (FrontMiddleBackQueue) PopFront() (ans int) { - if len(a) == 0 { +func (this *FrontMiddleBackQueue) PopMiddle() int { + if this.q1.Empty() && this.q2.Empty() { return -1 } - ans = a[0] - a = a[1:] - return + var val int + if this.q1.Size() == this.q2.Size() { + val = this.q1.PopBack() + } else { + val = this.q2.PopFront() + } + this.rebalance() + return val } -func (FrontMiddleBackQueue) PopMiddle() (ans int) { - if len(a) == 0 { +func (this *FrontMiddleBackQueue) PopBack() int { + if this.q2.Empty() { return -1 } - p := (len(a) - 1) / 2 - ans = a[p] - a = append(a[:p], a[p+1:]...) + val := this.q2.PopBack() + this.rebalance() + return val +} + +func (this *FrontMiddleBackQueue) rebalance() { + if this.q1.Size() > this.q2.Size() { + this.q2.PushFront(this.q1.PopBack()) + } + if this.q2.Size() > this.q1.Size()+1 { + this.q1.PushBack(this.q2.PopFront()) + } +} + +// template +type Deque struct{ l, r []int } + +func (q Deque) Empty() bool { + return len(q.l) == 0 && len(q.r) == 0 +} + +func (q Deque) Size() int { + return len(q.l) + len(q.r) +} + +func (q *Deque) PushFront(v int) { + q.l = append(q.l, v) +} + +func (q *Deque) PushBack(v int) { + q.r = append(q.r, v) +} + +func (q *Deque) PopFront() (v int) { + if len(q.l) > 0 { + q.l, v = q.l[:len(q.l)-1], q.l[len(q.l)-1] + } else { + v, q.r = q.r[0], q.r[1:] + } return } -func (FrontMiddleBackQueue) PopBack() (ans int) { - if len(a) == 0 { - return -1 +func (q *Deque) PopBack() (v int) { + if len(q.r) > 0 { + q.r, v = q.r[:len(q.r)-1], q.r[len(q.r)-1] + } else { + v, q.l = q.l[0], q.l[1:] } - ans = a[len(a)-1] - a = a[:len(a)-1] return } -``` -### **JavaScript** +func (q Deque) Front() int { + if len(q.l) > 0 { + return q.l[len(q.l)-1] + } + return q.r[0] +} -```js -var FrontMiddleBackQueue = function () { - this.left = []; - this.right = []; -}; +func (q Deque) Back() int { + if len(q.r) > 0 { + return q.r[len(q.r)-1] + } + return q.l[0] +} -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushFront = function (val) { - this.left.unshift(val); - this.rebalance(); -}; +func (q Deque) Get(i int) int { + if i < len(q.l) { + return q.l[len(q.l)-1-i] + } + return q.r[i-len(q.l)] +} /** - * @param {number} val - * @return {void} + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * obj := Constructor(); + * obj.PushFront(val); + * obj.PushMiddle(val); + * obj.PushBack(val); + * param_4 := obj.PopFront(); + * param_5 := obj.PopMiddle(); + * param_6 := obj.PopBack(); */ -FrontMiddleBackQueue.prototype.pushMiddle = function (val) { - this.left.push(val); - this.rebalance(); -}; +``` -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushBack = function (val) { - this.right.push(val); - this.rebalance(); -}; +### **TypeScript** -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popFront = function () { - if (this.isEmpty()) return -1; - let num = this.left.length == 0 ? this.right.shift() : this.left.shift(); - this.rebalance(); - return num; -}; +```ts +class FrontMiddleBackQueue { + private q1: Deque; + private q2: Deque; -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popMiddle = function () { - if (this.isEmpty()) return -1; - let num = this.left.length == this.right.length ? this.left.pop() : this.right.shift(); - this.rebalance(); - return num; -}; + constructor() { + this.q1 = new Deque(); + this.q2 = new Deque(); + } + + pushFront(val: number): void { + this.q1.pushFront(val); + this.rebalance(); + } + + pushMiddle(val: number): void { + this.q1.pushBack(val); + this.rebalance(); + } + + pushBack(val: number): void { + this.q2.pushBack(val); + this.rebalance(); + } + + popFront(): number { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = this.q1.isEmpty() ? this.q2.popFront() : this.q1.popFront(); + this.rebalance(); + return val!; + } + + popMiddle(): number { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = + this.q1.getSize() === this.q2.getSize() ? this.q1.popBack() : this.q2.popFront(); + this.rebalance(); + return val!; + } + + popBack(): number { + if (this.q2.isEmpty()) { + return -1; + } + const val = this.q2.popBack(); + this.rebalance(); + return val!; + } + + private rebalance(): void { + if (this.q1.getSize() > this.q2.getSize()) { + this.q2.pushFront(this.q1.popBack()!); + } + if (this.q2.getSize() > this.q1.getSize() + 1) { + this.q1.pushBack(this.q2.popFront()!); + } + } +} + +class Node { + value: T; + next: Node | null; + prev: Node | null; + + constructor(value: T) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + private front: Node | null; + private back: Node | null; + private size: number; + + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front!.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back!.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.front!.value; + this.front = this.front!.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.back!.value; + this.back = this.back!.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue(): T | undefined { + return this.front?.value; + } + + backValue(): T | undefined { + return this.back?.value; + } + + getSize(): number { + return this.size; + } + + isEmpty(): boolean { + return this.size === 0; + } +} /** - * @return {number} + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * var obj = new FrontMiddleBackQueue() + * obj.pushFront(val) + * obj.pushMiddle(val) + * obj.pushBack(val) + * var param_4 = obj.popFront() + * var param_5 = obj.popMiddle() + * var param_6 = obj.popBack() */ -FrontMiddleBackQueue.prototype.popBack = function () { - if (this.isEmpty()) return -1; - let num = this.right.pop(); - this.rebalance(); - return num; -}; +``` + +### **JavaScript** -FrontMiddleBackQueue.prototype.rebalance = function () { - while (this.left.length > this.right.length) { - this.right.unshift(this.left.pop()); +```js +class FrontMiddleBackQueue { + constructor() { + this.q1 = new Deque(); + this.q2 = new Deque(); } - while (this.right.length > this.left.length + 1) { - this.left.push(this.right.shift()); + + pushFront(val) { + this.q1.pushFront(val); + this.rebalance(); } -}; -FrontMiddleBackQueue.prototype.isEmpty = function () { - return this.left.length == 0 && this.right.length == 0; -}; + pushMiddle(val) { + this.q1.pushBack(val); + this.rebalance(); + } + + pushBack(val) { + this.q2.pushBack(val); + this.rebalance(); + } + + popFront() { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = this.q1.isEmpty() ? this.q2.popFront() : this.q1.popFront(); + this.rebalance(); + return val !== undefined ? val : -1; + } + + popMiddle() { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = + this.q1.getSize() === this.q2.getSize() ? this.q1.popBack() : this.q2.popFront(); + this.rebalance(); + return val !== undefined ? val : -1; + } + + popBack() { + if (this.q2.isEmpty()) { + return -1; + } + const val = this.q2.popBack(); + this.rebalance(); + return val !== undefined ? val : -1; + } + + rebalance() { + if (this.q1.getSize() > this.q2.getSize()) { + this.q2.pushFront(this.q1.popBack()); + } + if (this.q2.getSize() > this.q1.getSize() + 1) { + this.q1.pushBack(this.q2.popFront()); + } + } +} + +class Node { + constructor(value) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val) { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val) { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront() { + if (this.isEmpty()) { + return undefined; + } + const value = this.front.value; + this.front = this.front.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack() { + if (this.isEmpty()) { + return undefined; + } + const value = this.back.value; + this.back = this.back.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue() { + return this.front?.value; + } + + backValue() { + return this.back?.value; + } + + getSize() { + return this.size; + } + + isEmpty() { + return this.size === 0; + } +} /** * Your FrontMiddleBackQueue object will be instantiated and called as such: diff --git a/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.go b/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.go index ef8f6968104fd..a3ce45b6977c5 100644 --- a/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.go +++ b/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.go @@ -1,49 +1,137 @@ -type FrontMiddleBackQueue struct{} +type FrontMiddleBackQueue struct { + q1, q2 Deque +} -var a []int +func Constructor() FrontMiddleBackQueue { + return FrontMiddleBackQueue{} +} -func Constructor() (_ FrontMiddleBackQueue) { - a = nil - return +func (this *FrontMiddleBackQueue) PushFront(val int) { + this.q1.PushFront(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushFront(v int) { - a = append([]int{v}, a...) +func (this *FrontMiddleBackQueue) PushMiddle(val int) { + this.q1.PushBack(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushMiddle(v int) { - p := len(a) / 2 - a = append(a[:p], append([]int{v}, a[p:]...)...) +func (this *FrontMiddleBackQueue) PushBack(val int) { + this.q2.PushBack(val) + this.rebalance() } -func (FrontMiddleBackQueue) PushBack(v int) { - a = append(a, v) +func (this *FrontMiddleBackQueue) PopFront() int { + if this.q1.Empty() && this.q2.Empty() { + return -1 + } + var val int + if !this.q1.Empty() { + val = this.q1.PopFront() + } else { + val = this.q2.PopFront() + } + this.rebalance() + return val } -func (FrontMiddleBackQueue) PopFront() (ans int) { - if len(a) == 0 { +func (this *FrontMiddleBackQueue) PopMiddle() int { + if this.q1.Empty() && this.q2.Empty() { return -1 } - ans = a[0] - a = a[1:] - return + var val int + if this.q1.Size() == this.q2.Size() { + val = this.q1.PopBack() + } else { + val = this.q2.PopFront() + } + this.rebalance() + return val } -func (FrontMiddleBackQueue) PopMiddle() (ans int) { - if len(a) == 0 { +func (this *FrontMiddleBackQueue) PopBack() int { + if this.q2.Empty() { return -1 } - p := (len(a) - 1) / 2 - ans = a[p] - a = append(a[:p], a[p+1:]...) + val := this.q2.PopBack() + this.rebalance() + return val +} + +func (this *FrontMiddleBackQueue) rebalance() { + if this.q1.Size() > this.q2.Size() { + this.q2.PushFront(this.q1.PopBack()) + } + if this.q2.Size() > this.q1.Size()+1 { + this.q1.PushBack(this.q2.PopFront()) + } +} + +// template +type Deque struct{ l, r []int } + +func (q Deque) Empty() bool { + return len(q.l) == 0 && len(q.r) == 0 +} + +func (q Deque) Size() int { + return len(q.l) + len(q.r) +} + +func (q *Deque) PushFront(v int) { + q.l = append(q.l, v) +} + +func (q *Deque) PushBack(v int) { + q.r = append(q.r, v) +} + +func (q *Deque) PopFront() (v int) { + if len(q.l) > 0 { + q.l, v = q.l[:len(q.l)-1], q.l[len(q.l)-1] + } else { + v, q.r = q.r[0], q.r[1:] + } return } -func (FrontMiddleBackQueue) PopBack() (ans int) { - if len(a) == 0 { - return -1 +func (q *Deque) PopBack() (v int) { + if len(q.r) > 0 { + q.r, v = q.r[:len(q.r)-1], q.r[len(q.r)-1] + } else { + v, q.l = q.l[0], q.l[1:] } - ans = a[len(a)-1] - a = a[:len(a)-1] return -} \ No newline at end of file +} + +func (q Deque) Front() int { + if len(q.l) > 0 { + return q.l[len(q.l)-1] + } + return q.r[0] +} + +func (q Deque) Back() int { + if len(q.r) > 0 { + return q.r[len(q.r)-1] + } + return q.l[0] +} + +func (q Deque) Get(i int) int { + if i < len(q.l) { + return q.l[len(q.l)-1-i] + } + return q.r[i-len(q.l)] +} + +/** + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * obj := Constructor(); + * obj.PushFront(val); + * obj.PushMiddle(val); + * obj.PushBack(val); + * param_4 := obj.PopFront(); + * param_5 := obj.PopMiddle(); + * param_6 := obj.PopBack(); + */ \ No newline at end of file diff --git a/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.js b/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.js index 0417f9039f1be..1c5dcfd1f2637 100644 --- a/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.js +++ b/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.js @@ -1,77 +1,149 @@ -var FrontMiddleBackQueue = function () { - this.left = []; - this.right = []; -}; +class FrontMiddleBackQueue { + constructor() { + this.q1 = new Deque(); + this.q2 = new Deque(); + } -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushFront = function (val) { - this.left.unshift(val); - this.rebalance(); -}; + pushFront(val) { + this.q1.pushFront(val); + this.rebalance(); + } -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushMiddle = function (val) { - this.left.push(val); - this.rebalance(); -}; + pushMiddle(val) { + this.q1.pushBack(val); + this.rebalance(); + } -/** - * @param {number} val - * @return {void} - */ -FrontMiddleBackQueue.prototype.pushBack = function (val) { - this.right.push(val); - this.rebalance(); -}; + pushBack(val) { + this.q2.pushBack(val); + this.rebalance(); + } -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popFront = function () { - if (this.isEmpty()) return -1; - let num = this.left.length == 0 ? this.right.shift() : this.left.shift(); - this.rebalance(); - return num; -}; + popFront() { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = this.q1.isEmpty() ? this.q2.popFront() : this.q1.popFront(); + this.rebalance(); + return val !== undefined ? val : -1; + } -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popMiddle = function () { - if (this.isEmpty()) return -1; - let num = this.left.length == this.right.length ? this.left.pop() : this.right.shift(); - this.rebalance(); - return num; -}; + popMiddle() { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = + this.q1.getSize() === this.q2.getSize() ? this.q1.popBack() : this.q2.popFront(); + this.rebalance(); + return val !== undefined ? val : -1; + } -/** - * @return {number} - */ -FrontMiddleBackQueue.prototype.popBack = function () { - if (this.isEmpty()) return -1; - let num = this.right.pop(); - this.rebalance(); - return num; -}; + popBack() { + if (this.q2.isEmpty()) { + return -1; + } + const val = this.q2.popBack(); + this.rebalance(); + return val !== undefined ? val : -1; + } -FrontMiddleBackQueue.prototype.rebalance = function () { - while (this.left.length > this.right.length) { - this.right.unshift(this.left.pop()); + rebalance() { + if (this.q1.getSize() > this.q2.getSize()) { + this.q2.pushFront(this.q1.popBack()); + } + if (this.q2.getSize() > this.q1.getSize() + 1) { + this.q1.pushBack(this.q2.popFront()); + } } - while (this.right.length > this.left.length + 1) { - this.left.push(this.right.shift()); +} + +class Node { + constructor(value) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val) { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val) { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront() { + if (this.isEmpty()) { + return undefined; + } + const value = this.front.value; + this.front = this.front.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; } -}; -FrontMiddleBackQueue.prototype.isEmpty = function () { - return this.left.length == 0 && this.right.length == 0; -}; + popBack() { + if (this.isEmpty()) { + return undefined; + } + const value = this.back.value; + this.back = this.back.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue() { + return this.front?.value; + } + + backValue() { + return this.back?.value; + } + + getSize() { + return this.size; + } + + isEmpty() { + return this.size === 0; + } +} /** * Your FrontMiddleBackQueue object will be instantiated and called as such: diff --git a/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.ts b/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.ts new file mode 100644 index 0000000000000..c824a6d2f1dbc --- /dev/null +++ b/solution/1600-1699/1670.Design Front Middle Back Queue/Solution.ts @@ -0,0 +1,168 @@ +class FrontMiddleBackQueue { + private q1: Deque; + private q2: Deque; + + constructor() { + this.q1 = new Deque(); + this.q2 = new Deque(); + } + + pushFront(val: number): void { + this.q1.pushFront(val); + this.rebalance(); + } + + pushMiddle(val: number): void { + this.q1.pushBack(val); + this.rebalance(); + } + + pushBack(val: number): void { + this.q2.pushBack(val); + this.rebalance(); + } + + popFront(): number { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = this.q1.isEmpty() ? this.q2.popFront() : this.q1.popFront(); + this.rebalance(); + return val!; + } + + popMiddle(): number { + if (this.q1.isEmpty() && this.q2.isEmpty()) { + return -1; + } + const val = + this.q1.getSize() === this.q2.getSize() ? this.q1.popBack() : this.q2.popFront(); + this.rebalance(); + return val!; + } + + popBack(): number { + if (this.q2.isEmpty()) { + return -1; + } + const val = this.q2.popBack(); + this.rebalance(); + return val!; + } + + private rebalance(): void { + if (this.q1.getSize() > this.q2.getSize()) { + this.q2.pushFront(this.q1.popBack()!); + } + if (this.q2.getSize() > this.q1.getSize() + 1) { + this.q1.pushBack(this.q2.popFront()!); + } + } +} + +class Node { + value: T; + next: Node | null; + prev: Node | null; + + constructor(value: T) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + private front: Node | null; + private back: Node | null; + private size: number; + + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front!.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back!.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.front!.value; + this.front = this.front!.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.back!.value; + this.back = this.back!.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue(): T | undefined { + return this.front?.value; + } + + backValue(): T | undefined { + return this.back?.value; + } + + getSize(): number { + return this.size; + } + + isEmpty(): boolean { + return this.size === 0; + } +} + +/** + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * var obj = new FrontMiddleBackQueue() + * obj.pushFront(val) + * obj.pushMiddle(val) + * obj.pushBack(val) + * var param_4 = obj.popFront() + * var param_5 = obj.popMiddle() + * var param_6 = obj.popBack() + */