AcWing 154. 滑动窗口 && AcWing 1238. 日志统计

滑动窗口

一般使用队列或者双指针解决。

本质是限定长度的队列,利用先进先出的特性,将过早的信息排除,只考虑近期信息。
当队未满时,将符合条件的元素入队;达到最大长度开始出队。

对于存在映射关系的元素,单纯利用queue可能较难实现,这时可以采用双指针。

队列:154. 滑动窗口 - AcWing

题面:
给定一个大小为 n106 的数组。
有一个大小为 k滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k 个数字。
每次滑动窗口向右移动一个位置。
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值最小值

#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
int a[N], n, k;
int main()
{
deque<int> q; //双端队列
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
//先求最小值,即单增队列
for (int i = 1; i <= n; i++) {
//当队尾元素大于当前值时,因为窗口从左往右滑动,队尾不可能成为最小值,故出队
while (q.size() && q.back() > a[i])
q.pop_back();
q.push_back(a[i]);
//当队元素满k个或队头在k个数之前,即队头元素在窗口外,队头出队
if (i - k >= 1 && q.front() == a[i - k])
q.pop_front();
//前三个数已经被输入,窗口形成,开始输出队头对应的值
if (i >= k)
cout << q.front() << " ";
}
q.clear();
cout << endl;
//最大值同理
for (int i = 1; i <= n; i++) {
while (q.size() && q.back() < a[i])
q.pop_back();
q.push_back(a[i]);
if (i - k >= 0 && q.front() == a[i - k])
q.pop_front();
if (i >= k)
cout << q.front() << " ";
}
}

双指针:1238. 日志统计 - AcWing

题面:
对于一份帖子,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内收到不少于 K 个赞,该帖就曾是”热帖”。日志共有 N 行,格式为ts id,表示在 ts 时刻编号 id 的帖子收到一个“赞”。
给定日志,请你统计出所有曾是”热帖”的帖子编号。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 5;
int n, d, k;
int cnt[N]; //存储符合条件的点赞数
set<int> res;
PII logs[N]; //存储点赞时间与被赞帖子的映射关系
int main()
{
cin >> n >> d >> k;
for (int i = 0; i < n; i++)
cin >> logs[i].first >> logs[i].second;
sort(logs, logs + n); //默认按照时间排序
for (int i = 0, j = 0; i < n; i++) {
int id = logs[i].second;
cnt[id]++;
while (logs[i].first - logs[j].first >= d)
//排除不再合规的早期点赞数,同时移动慢指针(即窗口左侧)
cnt[logs[j++].second]--;
//直接输出的话可能输出多次,故使用set自动排序去重
if (cnt[id] >= k) res.insert(id);
}
for (auto i : res) cout << i << endl;
}
posted @   蒟蒻爬行中  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示