前言
欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
今天是六月集训第十六天:队列🔥🔥🔥
一、练习题目
二、算法思路
- 1、933. 最近的请求次数:用队列来解决🔥
- 2、1700. 无法吃午餐的学生数量:这道题有点循环队列的意思,根据题意学生数组本身就构成了一个循环队列。🔥
- 3、2073. 买票需要的时间:设计一个结构体用来记录买票人在数组中的位置和需要买票的总数,用这个结构体定义一个数组模拟队列。🔥🔥
- 4、239. 滑动窗口最大值:利用一个双端队列,队列中维护一个单调递减的值🔥🔥🔥
三、源码剖析
// 933. 最近的请求次数
class RecentCounter {
public:
queue<int> q;
RecentCounter() {
}
int ping(int t) {
q.push(t); //(1)
while(t - q.front() > 3000) { //(2)
q.pop();
}
return q.size();
}
};
- 1、把当前时间加入到队尾;
- 2、检查队首是否是当前时间的3000毫秒之内,如果不是的话就删除调,最后返回队列的长度即可。
// 1700. 无法吃午餐的学生数量
class Solution {
public:
int countStudents(vector<int>& students, vector<int>& sandwiches) {
int i = 0, j = 0;
int limit = 0;
while(i < students.size() && j < sandwiches.size()) {
if(students[i] == sandwiches[j]) { //(1)
++i;
++j;
} else {
students.push_back(students[i]); //(2)
++i;
++limit;
}
if(limit > 1000) {
break;
}
}
return students.size() - i;
}
};
- 1、当学生和三明治都不为空的时候,首先需要判断三明治和学生是否匹配,如果匹配的话,指向他们数组的指针都进行自增;
- 2、如果不匹配的话,当前学生就插到队尾,同时limit要进行自增,目的是limit是判断退出while的条件,不用limit会无限循环的。
// 2073. 买票需要的时间
class Solution {
struct People
{
int pos, ticket;
};
int front, rear;
People data[20000];
public:
int timeRequiredToBuy(vector<int>& tickets, int k) {
front = rear = 0;
int time = 0;
for(int i = 0; i < tickets.size(); ++i) {
People a;
a.pos = i;
a.ticket = tickets[i];
data[rear++] = a;
}
while (front < rear)
{
People p = data[front++];
time++;
--p.ticket;
if(p.ticket == 0) {
if(p.pos == k) {
return time;
}
} else {
data[rear++] = p;
}
}
return -1;
}
};
- 1、设计一个结构体;
- 2、定义一个结构体数组来模拟队列;
- 3、将题目中的tickets转化到结构数组队列中;
- 4、当队列不为空时候继续遍历,进行循环一次相当于模拟购票一次,时间加一,如果当前这个人票买完了,同时是我们要找的那个人,返回购票的总时间否则放到队尾继续模拟。
// 239. 滑动窗口最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> q;
vector<int> ret;
for(int i = 0; i < nums.size() - k + 1; ++i) {
ret.push_back(-1);
} //(1)
for(int i = 0; i < nums.size(); ++i) {
while(!q.empty() && i - q.front() > k - 1) { //(2)
q.pop_front();
}
while(!q.empty() && nums[q.back()] <= nums[i]) {
q.pop_back();
} //(3)
q.push_back(i); //(4)
if(i >= k - 1) { //(5)
ret[i - k + 1] = nums[q.front()];
}
}
return ret;
}
};
- 1、初始化结果数组;
- 2、每次加入一个元素,就判断队列元素个数是否超过k,如果超过,则将队首元素剔除;
- 3、如果加入第i个元素,会导致队列变成非单调递减,则将队尾元素删除;
- 4、 以上两步完成后,将当前元素塞入队列尾部,这时候队列一定单调递减;
- 5、如果这时候窗口长度刚好等于k,则将队列的队首元素塞入结果数组。