Social Network(运用map容器)

题目链接: Social Network (hard version)

题目:

你正在一个流行的社交网络中通过智能手机发送信息。你的智能手机最多可以显示k个最近与朋友的对话。最初,屏幕是空的(即显示的对话数等于0)。 每次谈话都是你和你的一些朋友之间的。最多只能和你的朋友进行一次谈话。所以每次谈话都是由你的朋友来定义的。 现在你(突然!)有能力看到未来。你知道在一天中你将收到n条信息,第i条信息将从id为idi(1≤idi≤10^9)的朋友处收到。 如果在智能手机当前显示的对话中收到来自IDI的消息,则不会发生任何事情:屏幕上的对话不会更改,也不会更改其顺序,您将阅读该消息并继续等待新消息。 否则(即,如果屏幕上没有与IDI的对话): 首先,如果屏幕上显示的对话数为k,则从屏幕上删除最后一个对话(位置为k)。 现在,屏幕上的对话数保证小于k,并且与朋友idi的对话不会显示在屏幕上。 与朋友idi的对话出现在屏幕的第一个(最上面的)位置,所有其他显示的对话都向下移动一个位置。 你的任务是在处理完所有n条消息后查找对话列表(按对话在屏幕上显示的顺序)

Input
输入的第一行包含两个整数n和k(1≤n,k≤2e5)-您的智能手机可以显示的消息数和对话数。 输入的第二行包含n个整数id1,id2,…,idn(1≤id i≤10^9),其中idi是向您发送第i条消息的朋友的id。

Output
在输出的第一行中,打印一个整数m(1≤m≤m in(n,k))——接收所有n条消息后显示的会话数。 在第二行中,打印m个整数ids1、ids2、…、idsm,其中idsi应等于收到所有n条消息后显示在位置i上的对话对应的朋友的id。

Examples:
Input
7 2
1 2 3 2 1 3 2
Output
2
2 1
Input
10 4
2 3 3 1 1 2 1 2 3 3
Output
3
1 3 2

解题思路:

该题有两个版本, 其中简单版本k值较小(只有200, 而不是困难版本的2e5), 可以考虑用去直接模拟(时间复杂度较高), AC代码如下:

easy version AC代码:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <stack>
#define ll long long
using namespace std;
stack<int> s;
bool search(int n)//找查栈中是否有元素n
{
	bool flag = 0;
	if (s.empty()) return 0;
	int temp = s.top(); s.pop();
	if (temp == n) { s.push(temp); return 1; }
	else flag = search(n);
	s.push(temp);
	return flag;
}
void del()//删除栈中最后一个元素
{
	if (s.size() == 1) { s.pop(); return; }
	int temp = s.top(); s.pop(); 
	del();
	s.push(temp);
}
void show()//显示栈内所有元素
{
	if (s.size() == 1) { printf("%d\n", s.top()); return; }
	printf("%d ", s.top()); s.pop();
	show();
}
int main(void)
{
	int n, k; cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		int a; scanf("%d", &a);
		if (!search(a)) {//如果栈中找不到元素a, 则进行操作.
			if(s.size() >= k) del(); //如果栈内元素已经有k个了, 则删除栈尾元素.(">="可以用"==")
			s.push(a);
		}
	}
	cout << s.size() << endl;
	show();
	return 0;
}

诚然, 栈的遍历在数据量庞大的时候是十分浪费时间的, 于是如果把这个代码交到k值最高可达2E5的hard版本, 会被T. 于是便有了如下全新的模拟思维: (当然该方法也可以通过easy版本)

解题思路:

运用map容器和数组进行模拟, map容器负责记录当前发消息的人是否已经在手机上显示, 而数组则记录手机上联系人的显示顺序.

hard version AC代码:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#define ll long long
using namespace std;
map<int, bool> m;//map<key, value> 通过给key(联系人)赋值value(是否在聊天列表中)
				//(0是不在, 1是在, 默认都不在)
int a[(ll)3E5];//记录联系人的消息顺序
int main(void)
{
	int n, k; cin >> n >> k;
	int num = 0; //num代表添加聊天信息数量(如果已经出现在屏幕上就不用添加了)(一开始屏幕是空的)
	int index = 1;//index代表消息的下限(随着消息越来越多, 最早的消息可能不会显示, 下限则会更新)
	for (int i = 0; i < n; i++) {
		int x; scanf("%d", &x);
		if (!m[x]) {//判断消息x是否在列表
			if (num >= k) { m[a[index++]] = 0; }
			a[++num] = x;
			m[x] = 1;
		}
	}
	printf("%d\n", num - index + 1);//因为显示消息一共是从num显示到index 所以总数其实是num-index+1
	for (int i = num; i >= index; i--) {
		printf("%d", a[i]);
		i == index ? printf("\n") : printf(" ");//格式控制
	}
	return 0;
}

该题就是一个map容器合理运用的一个很好的例子, 本人由于当时菜, 只做出了easy版本, hard版本由于map容器不熟练没有想到. 希望大家也以此为戒, 学好STL.

END

发布了20 篇原创文章 · 获赞 0 · 访问量 529

猜你喜欢

转载自blog.csdn.net/weixin_45799835/article/details/104168850