首页 > 代码库 > 51Nod - 1786 数据流中的算法 - 众数

51Nod - 1786 数据流中的算法 - 众数

 

1786 数据流中的算法 - 众数
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 
数据流统计功能上线后,为51nod提升用户体验做出了很大的贡献。但是新问题随之而来,夹克老爷还想知道在一个窗口内,访问次数最多用户(即窗口内的众数)。如果有多个众数,取用户ID最小的一个。(窗口的意思是一个固定长度的区间!)
 
(因为数据流是实时的、在线的,所以不允许使用离线算法^_^)
Input
第一行为整数n, k。(1 <= n <= 5 * 10^6,1 <= k <= 1000)
n代表有多少次操作,k代表窗口大小。

接下来的n行,每行代表一次操作。每行第一个整数为操作数。

操作数1:用户访问
输入格式: <1, id>
用户ID为[0, INT_MAX]闭区间内的整数。代表拥有此ID的用户对网站进行了一次访问,窗口进行相应移动。

操作数2:询问众数
输入格式:<2>
输出窗口内的众数,如果有多个,输出ID最小的那个。

p.s. 对于询问众数的操作,窗口保证不空
p.s.s. 对于询问众数的操作,窗口可能不满
Output
对于询问众数的操作,每行输出一个整数。
Input示例
10 5
1 2
1 1
1 2
1 1 
1 2
1 1
2
1 3
1 3
2
Output示例
1
1

题目大意:
起初看到这道题,没读懂是什么意思,一直在纳闷窗口是啥。后来才明白,是实现查询,查询时的前k个访问次数中,访问最多的用户的编号。
分析:
首先,考虑到的是只考虑查询前的前k次访问,复杂度是k*查询次数,如果大部分都是查询明显过不去。
之后,用优先队列去实现,优先队列内容是一个结构体,储存了用户的ID,和访问次数。但是,优先队列不支持删除操作,
所以怎么去实现删除已经超过k个用户的数据呢?我的方法是使用map记录每个用户的访问次数,删除k个之前的用户时,只在map里将其更新。然后,查询时
去循环取优先队列顶部元素,检查这个元素储存的访问次数是否与map里记录的次数相同,如果不相同则该节点作废,出队,再取队列顶部元素,直到相同为止,
然后,交上去,就超时了,将map改成hash_map,优化了输入之后再交,700ms通过。
其实,优先队列写法挂了之后,并没又马上用hash_map,就将程序改为了用set去实现,set的最大值就是set中最后一个元素,插入删除复杂度,log(n),2000ms,超时。。。。。。然后又将map改成hash_map,优化了输入输出之后再交,
700ms通过。。。。。。
ps:hash_map用VC++去交就可以成功编译
//优先队列实现
#include<iostream>
using namespace std;
#include<queue>
#include<cstdio>
#include<hash_map>
typedef long long LL;
inline LL getint()//快速读入
{
	LL w = 0, q = 0;
	char c = getchar();
	while ((c<‘0‘ || c>‘9‘) && c != ‘-‘) c = getchar();
	if (c == ‘-‘) q = 1, c = getchar();
	while (c >= ‘0‘&&c <= ‘9‘) w = w * 10 + c - ‘0‘, c = getchar();
	return q ? -w : w;
}
queue<LL> team;
struct data//优先队列里信息用的结构体
{
	LL sj;
	LL bh;
	bool operator<(const data &b)const
	{
		if (this->sj == b.sj) return this->bh>b.bh;
		return this->sj<b.sj;
	}
};
priority_queue<data> preteam;
hash_map<LL, LL> maps;
int n, k;
int main()
{
	int rq = 0;
	cin >> n >> k;
	LL pre;
	int ml;
	LL dx;
	data mx;
	for (int i = 1; i <= n; i++)
	{
		//scanf("%d", &ml);
		ml = getint();
		if (ml == 1)
		{
			//scanf("%lld", &dx);
			dx = getint();
			data np;
			maps[dx]++;
			np.bh = dx; np.sj = maps[dx];
			preteam.push(np);
			team.push(dx);
			if (team.size() == k + 1)
			{
				pre = team.front();
				maps[pre]--;
				team.pop();
			}
		}
		if (ml == 2)
		{
			mx = preteam.top();
                        /*循环取优先队列有效值*/
			while (mx.sj != maps[mx.bh] && !preteam.empty()) {
				preteam.pop();
				mx = preteam.top();
			}
			printf("%d\n", mx.bh);
		}
	}
	return 0;
}
        

  

 

//set实现
#include<iostream>
using namespace std;
#include<queue>
#include<cstdio>
#include<hash_map>
#include<map>
#include<set> 
typedef long long LL;
queue<LL> team;
inline LL getint()
{
	LL w = 0, q = 0;
	char c = getchar();
	while ((c<‘0‘ || c>‘9‘) && c != ‘-‘) c = getchar();
	if (c == ‘-‘) q = 1, c = getchar();
	while (c >= ‘0‘&&c <= ‘9‘) w = w * 10 + c - ‘0‘, c = getchar();
	return q ? -w : w;
}
struct data
{
	LL sj;
	LL bh;
	bool operator<(const data &b)const
	{
		if (this->sj == b.sj) return this->bh>b.bh;
		return this->sj<b.sj;
	}
};
set<struct data> preset;
hash_map<LL, LL> maps;
int n, k;
int main()
{
	set<struct data>::iterator pt;
	int rq = 0;
	//cin>>n>>k;
	n = getint();
	k = getint();
	LL pre;
	int ml;
	LL dx;
	struct data mx;
	for (int i = 1; i <= n; i++)
	{
		//scanf("%d",&ml);
		ml = getint();
		if (ml == 1)
		{
			dx = getint();
			//	scanf("%lld",&dx);
			struct data np;
			np.bh = dx; np.sj = maps[dx];
			preset.erase(np);
			maps[dx]++;
			np.sj = maps[dx];
			preset.insert(np);
			team.push(dx);
			if (team.size() == k + 1)
			{
				pre = team.front();
				np.bh = pre; np.sj = maps[pre];
				preset.erase(np);
				team.pop();
				maps[pre]--;
				if (maps[pre] == 0) continue;
				np.sj = maps[pre];
				preset.insert(np);
			}
		}
		if (ml == 2)
		{
			pt = preset.end();
			--pt;//迭代器自减至set最后一个元素的位置
			int bh = (*pt).bh;
			//	cout<<bh<<endl;
			printf("%d\n", bh);
		}
	}
	return 0;
}

  


51Nod - 1786 数据流中的算法 - 众数