文章目录
- Tag
- 题目来源
- 题目解读
- 解题思路
- 方法一:双指针
- 写在最后
Tag
【设计类】【队列】【数组】【2023-11-28】
题目来源
1670. 设计前中后队列
题目解读
设计一个队列,可以实在在前、中、后三个位置的 push 和 pop 操作。
解题思路
维护一个数组,在数组中使用指针指向前、后两个位置并维护两个的指向。本题还可以使用 vector
容器,可以省去移动的操作,这里没有介绍该方法,读者可以自行实现。
方法一:双指针
初始化
FrontMiddleBackQueue() {front = CENTER;rear = front - 1;
}
使用两个指针 front
和 rear
分别指向数组 data
的 “前后” 两个位置。初始化 data
数组,int data[5000]
,接着初始化 front = 2500
,rear = front - 1
。
getCount
int getCont(){return rear - front + 1;
}
push 和 pop 操作
前、后两个位置的 push
和 pop
操作很容易实现:
void pushFront(int val) {data[--front] = val;
}void pushBack(int val) {data[++rear] = val;
}
在 pushFront
之前先对 front
指针 --
,然后将 val
插入到该位置。在 pushBack
中需要先 ++ rear
,然后插入 val
。
int popFront() {if(getCont() == 0){return -1;}int val = data[front++]; // 弹出Front之后front变为前插下个数的后一个位置return val;
}int popBack() {if(getCont() == 0){return -1;}int val = data[rear--]; // 弹出Back之后rear变为尾插下个数的前一个位置return val;
}
pop
操作之前需要先判断 data
是否为空,如是则返回 -1
;否则弹出对应的元素并更改指针为 “下一个” 元素。
pushMiddle
记此时数组 data
的长度为 cnt
,我们需要根据 cnt
的不同对 pushMiddle
进行分情况讨论:
- 当
cnt = 1
时,此时的 middle 位置为font - 1
,记为pushPos = font - 1
; - 否则,
pushPos = font + (cnt / 2)
;
接着需要将 val
插入到 pushPos
位置,如果 cnt = 1
,可以直接 pushFront(val)
;否则不能直接在 pushPos
插入 val
,需要先将 pushPos
及之后的元素依次向后移动一位,将 pushPos
位置空出,然后将 val
插入到 pushPos
位置,或者将pushPos
及之前的元素依次向前移动一位,将 pushPos
位置空出,然后将 val
插入到 pushPos
位置。
以下是后移的示例代码:
void pushMiddle(int val) {int cnt = getCont();if(cnt == 1){pushFront(val);return;}int pushPos = front+(cnt/2);for(int i = rear+1; i > pushPos; --i){data[i] = data[i-1];}data[pushPos] = val;++rear;
}
popMiddle
pop
之前需要先判断数组是否为空,如是直接返回 -1
,否则需要先找到 popPos
即需要弹出的位置,由数学归纳知 popPos = front + (n - 1) / 2
,n
为数组此时的长度。
弹出 popPos
位置的元素之后,需要将 popPos
之后的元素依次左移一位填充空格,然后 --rear
。示例代码如下:
int popMiddle() {int cnt = getCont();if(cnt == 0){return -1;}int popPos = front + (cnt - 1)/2;int tmp = data[popPos];for(int i = popPos; i < rear; ++i){data[i] = data[i+1];}--rear;return tmp;
}
实现代码
class FrontMiddleBackQueue {#define CENTER 2500int data[5000];int front, rear;
public:FrontMiddleBackQueue() {front = CENTER;rear = front - 1;}int getCont(){return rear - front + 1;}void pushFront(int val) {data[--front] = val;}/*个数 插入位置X front-1 特殊情况XX front+1XXX front+1XXXX front+2... ...n个数 front+(n/2)
*/ void pushMiddle(int val) {int cnt = getCont();if(cnt == 1){pushFront(val);return;}int pushPos = front+(cnt/2);for(int i = rear+1; i > pushPos; --i){data[i] = data[i-1];}data[pushPos] = val;++rear;}void pushBack(int val) {data[++rear] = val;}int popFront() {if(getCont() == 0){return -1;}int val = data[front++]; // 弹出Front之后front变为前插下个数的后一个位置return val;}/*个数 pop位置X front 特殊情况XX frontXXX front+1XXXX front+1XXXXX front+2... ...n个数 front+(n-1/2)
*/int popMiddle() {int cnt = getCont();if(cnt == 0){return -1;}int popPos = front + (cnt - 1)/2;int tmp = data[popPos];for(int i = popPos; i < rear; ++i){data[i] = data[i+1];}--rear;return tmp;}int popBack() {if(getCont() == 0){return -1;}int val = data[rear--]; // 弹出Back之后rear变为尾插下个数的前一个位置return val;}
};
复杂度分析
时间复杂度:pushFront
、pushBack
、popFront
以及 popBack
一次操作的时间复杂度均为 O ( 1 ) O(1) O(1),pushMiddle
和 popMiddle
n
次操作的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
空间复杂度: O ( n ) O(n) O(n)。
写在最后
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。
最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。