[LeetCode] 1670. Design Front Middle Back Queue

Design a queue that supports push and pop operations in the front, middle, and back.

Implement the FrontMiddleBack class:

  • FrontMiddleBack() Initializes the queue.
  • void pushFront(int val) Adds val to the front of the queue.
  • void pushMiddle(int val) Adds val to the middle of the queue.
  • void pushBack(int val) Adds val to the back of the queue.
  • int popFront() Removes the front element of the queue and returns it. If the queue is empty, return -1.
  • int popMiddle() Removes the middle element of the queue and returns it. If the queue is empty, return -1.
  • int popBack() Removes the back element of the queue and returns it. If the queue is empty, return -1.

Notice that when there are two middle position choices, the operation is performed on the frontmost middle position choice. For example:

  • Pushing 6 into the middle of [1, 2, 3, 4, 5] results in [1, 2, 6, 3, 4, 5].
  • Popping the middle from [1, 2, 3, 4, 5, 6] returns 3 and results in [1, 2, 4, 5, 6].

Example 1:

Input:
["FrontMiddleBackQueue", "pushFront", "pushBack", "pushMiddle", "pushMiddle", "popFront", "popMiddle", "popMiddle", "popBack", "popFront"]
[[], [1], [2], [3], [4], [], [], [], [], []]
Output:
[null, null, null, null, null, 1, 3, 4, 2, -1]

Explanation:
FrontMiddleBackQueue q = new FrontMiddleBackQueue();
q.pushFront(1);   // [1]
q.pushBack(2);    // [1, 2]
q.pushMiddle(3);  // [1, 3, 2]
q.pushMiddle(4);  // [1, 4, 3, 2]
q.popFront();     // return 1 -> [4, 3, 2]
q.popMiddle();    // return 3 -> [4, 2]
q.popMiddle();    // return 4 -> [2]
q.popBack();      // return 2 -> []
q.popFront();     // return -1 -> [] (The queue is empty)

Constraints:

  • 1 <= val <= 109
  • At most 1000 calls will be made to pushFrontpushMiddlepushBackpopFrontpopMiddle, and popBack.

设计前中后队列。

请你设计一个队列,支持在前,中,后三个位置的 push 和 pop 操作。

请你完成 FrontMiddleBack 类:

FrontMiddleBack() 初始化队列。
void pushFront(int val) 将 val 添加到队列的 最前面 。
void pushMiddle(int val) 将 val 添加到队列的 正中间 。
void pushBack(int val) 将 val 添加到队里的 最后面 。
int popFront() 将 最前面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
int popMiddle() 将 正中间 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
int popBack() 将 最后面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
请注意当有 两个 中间位置的时候,选择靠前面的位置进行操作。比方说:

将 6 添加到 [1, 2, 3, 4, 5] 的中间位置,结果数组为 [1, 2, 6, 3, 4, 5] 。
从 [1, 2, 3, 4, 5, 6] 的中间位置弹出元素,返回 3 ,数组变为 [1, 2, 4, 5, 6] 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-front-middle-back-queue
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这是一道设计题,思路是用两个双端队列deque做。首先我需要创建两个deque,left 和 right。left 在左边,right 在右边,left 的右侧跟 right 的左侧相接。当元素个数为偶数的时候,left 和 right 的元素个数是相同的;但是当元素个数为奇数的时候,right 会比 left 多一个元素。

pushFront() - 只会从 left 的左侧加元素

pushBack() - 只会从 right 的右侧加元素

popFront() - 只会从 left 的左侧弹出元素

popBack() - 只会从 right 的右侧弹出元素

pushMiddle() - 如果两个 deque 元素个数相同,则加入 right;反之则加入 left

popMiddle() - 如果两个 deque 元素个数相同,则试图弹出 left 的最右侧元素(注意有可能为空);反之则弹出 right 最左侧的元素

最后我们还需要一个 balance() 函数来帮助平衡两个 deque 的元素个数,使得 right 最多比 left 多一个元素。

时间O(1) - amortized,因为这是ArrayDeque决定的

空间O(n)

Java实现

 1 class FrontMiddleBackQueue {
 2     Deque<Integer> left;
 3     Deque<Integer> right;
 4 
 5     public FrontMiddleBackQueue() {
 6         left = new ArrayDeque<>();
 7         right = new ArrayDeque<>();
 8     }
 9 
10     //   addFromHere -> left -- right
11     public void pushFront(int val) {
12         left.addFirst(val);
13         balance();
14     }
15 
16     public void pushMiddle(int val) {
17         if (left.size() == right.size()) {
18             right.addFirst((val));
19         } else {
20             left.addLast(val);
21         }
22     }
23 
24     public void pushBack(int val) {
25         right.addLast(val);
26         balance();
27     }
28 
29     public int popFront() {
30         Integer num = left.pollFirst();
31         if (num == null) {
32             num = right.pollFirst();
33             return num == null ? -1 : num;
34         } else {
35             balance();
36             return num;
37         }
38     }
39 
40     public int popMiddle() {
41         if (left.size() == right.size()) {
42             Integer num = left.pollLast();
43             return num == null ? -1 : num;
44         } else {
45             return right.pollFirst();
46         }
47     }
48 
49     public int popBack() {
50         Integer num = right.pollLast();
51         balance();
52         return num == null ? -1 : num;
53     }
54 
55     private void balance() {
56         if (left.size() > right.size()) {
57             right.addFirst(left.pollLast());
58         } else if (left.size() + 2 == right.size()) {
59             left.addLast(right.pollFirst());
60         }
61     }
62 }
63 
64 /**
65  * Your FrontMiddleBackQueue object will be instantiated and called as such:
66  * FrontMiddleBackQueue obj = new FrontMiddleBackQueue();
67  * obj.pushFront(val);
68  * obj.pushMiddle(val);
69  * obj.pushBack(val);
70  * int param_4 = obj.popFront();
71  * int param_5 = obj.popMiddle();
72  * int param_6 = obj.popBack();
73  */

 

LeetCode 题目总结

上一篇:选第k小元素:特定分治策略


下一篇:287. 寻找重复数 (JAVA)