队列基础知识
- 入队
- 出队
- 假溢出
- 循环队列
实现方式
普通队列
class Queue{
public:
Queue(int n) : arr(n), head(0), tail(0){}
//入队
void push(int x){
if(full()){
cout << "queue full" << endl;
}
arr[tail] = x;
tail += 1;
return ;
}
//出队
void pop(){
if(empty()) return;
head +=1 ;
}
//判空
bool empty(){
return head == tail;
}
//判满
bool full(){
return tail = arr.size();
}
//查看队首元素
int front(){
return arr[head];
}
int size(){
return tail - head;
}
void output(){
cout<<"Queue: ";
for(int i = head ; i < tail ; i++){
cout << arr[i] << "";
}
cout << endl;
}
private:
int head, tail;
vector<int> arr;
}
循环队列
class Queue{
public:
Queue(int n) : arr(n), head(0), tail(0), cnt(0){}
//入队
void push(int x){
if(full()){
cout << "queue full" << endl;
}
arr[tail] = x;
tail += 1;
cnt += 1;
if(tail == arr.size()) tail = 0;
return ;
}
//出队
void pop(){
if(empty()) return;
head +=1 ;
cnt -= 1;
if(head == arr.size()) tail = 0
}
//判空
bool empty(){
return cnt = 0;
}
//判满
bool full(){
return cnt = arr.size();
}
//查看队首元素
int front(){
return arr[head];
}
int size(){
return cnt;
}
void output(){
cout<<"Queue: ";
for(int i = 0 , j =head ; i < cnt ; i++){
cout << arr[j] << "";
j += 1;
if(j == arr.size()) j = 0;
}
cout << endl;
}
void clear(){
head = tail = cnt = 0;
}
private:
int head, tail;
int cnt;
vector<int> arr;
}
队列的典型应用场景
场景一: CPU的超线程技术
虚拟四核: 给每个核心增加一条指令队列
多路CPU: CPU1 CPU2 CPU3…
一个CPU包含多个计算核心, 多路CPU包含多个CPU
场景二: 线程池的任务队列
普通的多线程程序问题: 频繁的申请和销毁, 效率大打折扣
任务队列: 任务的缓冲区
经典面试题 - 链表复习题
86.分隔链表
设置两个头指针,将所有小于的插入到第一个链表中,将所有大于的插入到第二个链表中,最后将这两个链表合成一段
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode r1 , r2 , *p1 = &r1 , *p2=&r2 , *p = head, *q;
while(p){
q = p->next;
if(p->val < x){
p->next = p1->next;
p1->next = p;
p1 = p;
} else {
p->next = p2->next;
p2->next = p;
p2 = p;
}
p = q;
}
p1->next = r2.next;
return r1.next;
}
};
138. 复制带随机指针的链表
思路:
- 将原来的链表两两一组进行复制(包含random节点),如下
原链表 1->2->3->4
复制后的链表 1->1’->2->2’->3->3’->4->4’ - 此时原节点和复制节点的random节点都指向同一位,需要将复制节点的random指向下一位
- 将链表每两个节点拆成一个新链表
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr) return nullptr;
Node *p = head, *q, *new_head;
while(p){
q = new Node(p->val);
q->random = p->random;
q->next = p->next;
p->next = q;
p = q->next;
}
p = head->next;
while(p){
if(p->random) p->random = p->random->next;
(p = p->next) && (p = p->next);
}
new_head = head->next;
p = head;
while(p){
q = p->next;
p->next = q->next;
if(p->next) q->next = p->next->next;
p = p->next;
}
return new_head;
}
};
经典面试题 - 队列
622. 设计循环队列
class MyCircularQueue {
public:
vector<int> arr;
int head, tail, cnt;
MyCircularQueue(int k) : arr(k), head(0), tail(0), cnt(0){}
bool enQueue(int value) {
if(isFull()) return false;
arr[tail] = value;
tail = (tail + 1) % arr.size();
cnt += 1;
return true;
}
bool deQueue() {
if(isEmpty()) return false;
head = (head + 1) % arr.size();
cnt -= 1;
return true;
}
int Front() {
if(isEmpty()) return -1;
return arr[head];
}
int Rear() {
if(isEmpty()) return -1;
return arr[(tail - 1 + arr.size()) % arr.size()];
}
bool isEmpty() {
return cnt == 0;
}
bool isFull() {
return cnt == arr.size();
}
};
641. 设计循环双端队列
class MyCircularDeque {
public:
vector<int> arr;
int cnt, head, tail;
MyCircularDeque(int k) : arr(k), head(0), tail(0), cnt(0){}
bool insertFront(int value) {
if(isFull()) return false;
head = head - 1;
if(head == -1) head = arr.size() - 1;
arr[head] = value;
cnt += 1;
return true;
}
bool insertLast(int value) {
if(isFull()) return false;
arr[tail] = value;
tail += 1;
if(tail == arr.size()) tail = 0;
cnt += 1;
return true;
}
bool deleteFront() {
if(isEmpty()) return false;
head = (head + 1) % arr.size();
cnt -= 1;
return true;
}
bool deleteLast() {
if(isEmpty()) return false;
tail = (tail - 1 + arr.size()) % arr.size();
cnt -= 1;
return true;
}
int getFront() {
if(isEmpty()) return -1;
return arr[head];
}
int getRear() {
if(isEmpty()) return -1;
return arr[(tail - 1 + arr.size()) % arr.size()];
}
bool isEmpty() {
return cnt == 0;
}
bool isFull() {
return cnt == arr.size();
}
};
1670.设计前中后队列
class Node{
public:
int val;
Node *next, *pre;
Node(int val = 0, Node *next = nullptr, Node *pre = nullptr) : val(val), next(next), pre(pre){}
void insert_pre(Node *p){
p->pre = pre;
p->next = this;
if(this->pre) this->pre->next = p;
this->pre = p;
return;
}
void insert_next(Node *p){
p->pre = this;
p->next = this->next;
if(this->next) this->next->pre = p;
this->next = p;
return;
}
void delete_pre(){
if(this->pre == nullptr) return;
Node *p = this->pre;
this->pre = p->pre;
if(p->pre) p->pre->next = this;
delete p;
return;
}
void delete_next(){
if(this->next == nullptr) return;
Node *p = this->next;
this->next = p->next;
if(p->next) p->next->pre = this;
delete p;
return;
}
};
class Queue {
public:
int cnt;
Node head, tail;
Queue(): cnt(0){
head.next = &tail;
head.pre = nullptr;
tail.next = nullptr;
tail.pre = &head;
}
void push_back(int val){
tail.insert_pre(new Node(val));
cnt += 1;
return;
}
void push_front(int val){
head.insert_next(new Node(val));
cnt += 1;
return;
}
int pop_back(){
if(isEmpty()) return -1;
int ret = tail.pre->val;
cnt -= 1;
tail.delete_pre();
return ret;
}
int pop_front(){
if(isEmpty()) return -1;
int ret = head.next->val;
cnt -= 1;
head.delete_next();
return ret;
}
int front(){
return head.next->val;
}
int back(){
return tail.pre->val;
}
bool isEmpty(){
return head.next == &tail;
}
int size(){
return cnt;
}
};
class FrontMiddleBackQueue {
public:
Queue q1, q2;
FrontMiddleBackQueue() {}
void pushFront(int val) {
q1.push_front(val);
update();
return;
}
void pushMiddle(int val) {
if(q1.size() > q2.size()){
q2.push_front(q1.back());
q1.pop_back();
}
q1.push_back(val);
return;
}
void pushBack(int val) {
q2.push_back(val);
update();
return;
}
int popFront() {
if(isEmpty()) return -1;
int ret = q1.pop_front();
update();
return ret;
}
int popMiddle() {
if(isEmpty()) return -1;
int ret = q1.pop_back();
update();
return ret;
}
int popBack() {
if(isEmpty()) return -1;
int ret;
if(q2.isEmpty()){
ret = q1.pop_back();
}else{
ret = q2.pop_back();
}
update();
return ret;
}
bool isEmpty(){
return q1.size() + q2.size() == 0;
}
void update() {
if(q1.size() < q2.size()){
q1.push_back(q2.front());
q2.pop_front();
}
if(q1.size() == q2.size() + 2){
q2.push_front(q1.back());
q1.pop_back();
}
return;
}
};
933.最近请求次数
- 每次请求时入队
- 与队首比较,超出3000毫秒的出队
- 返回队列长度
class RecentCounter {
public:
queue<int> q;
RecentCounter() {
}
int ping(int t) {
q.push(t);
while(t - q.front() > 3000) q.pop();
return q.size();
}
};
经典面试题-智力发散题
面试题 17.09. 第 k 个数
- 生成一个队列,设置p3,p5,p7三个指针
- 分别用指针指向的值乘3,乘5,乘7,取其中最小值压入,然后该指针向后移一位(如果两个指针算出来的值相同,那就同时往后移动一位)
class Solution {
public:
int getKthMagicNumber(int k) {
vector<int> arr;
arr.push_back(1);
int p3 = 0, p5 = 0, p7 = 0;
while(arr.size() < k){
int ans = 3 * arr[p3];
ans = min(ans, 5 * arr[p5]);
ans = min(ans, 7 * arr[p7]);
if(3 * arr[p3] == ans) p3++;
if(5 * arr[p5] == ans) p5++;
if(7 * arr[p7] == ans) p7++;
arr.push_back(ans);
}
return arr[k-1];
}
};
860.柠檬水找零
- 给10元 只能找零5元
- 给20元 1.找零一张10元 一张5元 2.三张5元 优先一张10元一张5元
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five = 0, ten = 0;
for (auto & bill: bills) {
if (bill == 5) {
five++;
} else if (bill == 10) {
if (five == 0) {
return false;
}
five--;
ten++;
} else {
if (five > 0 && ten > 0) {
five--;
ten--;
} else if (five >= 3) {
five -= 3;
} else {
return false;
}
}
}
return true;
}
};
621. 任务调度器
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
int cnt[26] = {0};
for(int i = 0;i < tasks.size(); i++) cnt[tasks[i] - 'A'] += 1;
sort(cnt, cnt + 26);
int m = 0;
for(int i = 25; i>=0 && cnt[i] == cnt[25]; i--, m++);
return max((int)tasks.size(), ( cnt[25] -1 ) * ( n + 1 ) + m);
}
};