日志统计 巧用Vector,,map 【蓝桥杯真题】(c++实现)

126 阅读3分钟

上文链接:全球变暖 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;
}