日志统计 巧用Vector,,map 【蓝桥杯真题】(c++实现)
程序员文章站
2022-07-12 16:47:59
...
上文链接:全球变暖 BFS非递归【蓝桥杯真题】(c++实现)
日志统计
小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是:
ts id
表示在ts时刻编号id的帖子收到一个"赞"。
现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。
具体来说,如果存在某个时刻T满足该帖在[T, T+D)这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。
给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。
【输入格式】
第一行包含三个整数N、D和K。
以下N行每行一条日志,包含两个整数ts和id。
对于50%的数据,1 <= K <= N <= 1000
对于100%的数据,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000
【输出格式】
按从小到大的顺序输出热帖id。每个id一行。
【输入样例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
【输出样例】
1
3
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
我的思路
-
题中可以有两种求解思路,一是根据某个时间段中查找满足大于k的id,记录其数量,二是在某个id对应的时刻中查找在某时间段的点赞数是否大于k,是则记录,两种方式均可。
-
我讲解比较麻烦的一个:第二个,首先将输入进行预处理,将id进行升序排序,将id对应的时刻进行升序排序,迭代查询某id对应的时刻里(尺取法查询:规定范围查询),在某个时间段是否出现大于k次,是则记录。
-
注意点,使用结构体或类对id、时刻进行排序时的绑定。
算法展示
第一个对应算法(100%正确):
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
int N,D,K,ans;
//存储日志
struct log{
int id,time;
};
//对id进行升序排序
bool cmp(log a,log b)
{
return a.time < b.time;
}
int main()
{
//快读配置
std::ios::sync_with_stdio(0);
//读取规模
cin>>N>>D>>K;
//存储多个日志并排序
vector<log> logs(N);
for(int i = 0;i<N;++i)
{
cin>>logs[i].time>>logs[i].id;
}
sort(logs.begin(),logs.end(),cmp);
//记录答案
set<int> ans;
//记录id出现的次数
map<int,int>cnt;
int j = 0;//哨兵
for(int i = 0;i<N;++i)
{
while(j<N&&logs[j].time-logs[i].time<D)
{
cnt[logs[j].id]++;
if(cnt[logs[j].id]>=K)ans.insert(logs[j].id);
j++;
}
cnt[logs[i].id]--;
}
for(set<int>::iterator i = ans.begin();i !=ans.end();i++)cout<<*i<<endl;
return 0;
}
第二个对应算法(67%正确):
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
int N,D,K,ans;
//存储日志
struct log{
int id,time;
};
//对id进行升序排序
bool cmp(log a,log b)
{
return a.id < b.id;
}
int main()
{
//快读配置
std::ios::sync_with_stdio(0);
//读取规模
cin>>N>>D>>K;
//存储多个日志并排序
vector<log> logs(N);
for(int i = 0;i<N;i++)
{
cin>>logs[i].time>>logs[i].id;
}
sort(logs.begin(),logs.end(),cmp);
set<int> ans;
int cid,j = 0,end = 0;//当前查找的id,索引j
while(j<N)//从头开始查找
{
cid = logs[j].id;
//查找一组id对应的开始结束日期
int start = j,end = start,ck = 1;
while(cid==logs[end].id)end++;
//记录在某时间段中获得赞大于等于K的id
for(int si = start;si<end-1;si++)
{
for(int ji = si+1;ji<end;ji++)
{
if(abs(logs[si].time-logs[ji].time) < D) ck++;
}
if(ck>=K)
{
ans.insert(logs[si].id);
break;
}
ck = 0;
}
j = end;
}
for(set<int>::iterator i = ans.begin();i !=ans.end();i++)cout<<*i<<endl;
return 0;
}