关于map容器的解法 C - Social Network (hard version)

C - Social Network (hard version)
题目链接:C - Social Network (hard version)

题目要求

The only difference between easy and hard versions are constraints on nn and kk.

You are messaging in one of the popular social networks via your smartphone. Your smartphone can show at most kk most recent conversations with your friends. Initially, the screen is empty (i.e. the number of displayed conversations equals 00).

Each conversation is between you and some of your friends. There is at most one conversation with any of your friends. So each conversation is uniquely defined by your friend.

You (suddenly!) have the ability to see the future. You know that during the day you will receive nn messages, the ii-th message will be received from the friend with ID idiidi (1≤idi≤1091≤idi≤109).

If you receive a message from idiidi in the conversation which is currently displayed on the smartphone then nothing happens: the conversations of the screen do not change and do not change their order, you read the message and continue waiting for new messages.

Otherwise (i.e. if there is no conversation with idiidi on the screen):

Firstly, if the number of conversations displayed on the screen is kk, the last conversation (which has the position kk) is removed from the screen.
Now the number of conversations on the screen is guaranteed to be less than kk and the conversation with the friend idiidi is not displayed on the screen.
The conversation with the friend idiidi appears on the first (the topmost) position on the screen and all the other displayed conversations are shifted one position down.
Your task is to find the list of conversations (in the order they are displayed on the screen) after processing all nn messages.

Input
The first line of the input contains two integers nn and kk (1≤n,k≤2⋅105)1≤n,k≤2⋅105) — the number of messages and the number of conversations your smartphone can show.

The second line of the input contains nn integers id1,id2,…,idnid1,id2,…,idn (1≤idi≤1091≤idi≤109), where idiidi is the ID of the friend which sends you the ii-th message.

Output
In the first line of the output print one integer mm (1≤m≤min(n,k)1≤m≤min(n,k)) — the number of conversations shown after receiving all nn messages.

In the second line print mm integers ids1,ids2,…,idsmids1,ids2,…,idsm, where idsiidsi should be equal to the ID of the friend corresponding to the conversation displayed on the position ii after receiving all nn messages.

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
Note
In the first example the list of conversations will change in the following way (in order from the first to last message):

[][];
[1][1];
[2,1][2,1];
[3,2][3,2];
[3,2][3,2];
[1,3][1,3];
[1,3][1,3];
[2,1][2,1].
In the second example the list of conversations will change in the following way:

[][];
[2][2];
[3,2][3,2];
[3,2][3,2];
[1,3,2][1,3,2];
and then the list will not change till the end.

解题思路

该题我第一遍写,复杂度O(m*n),第2遍复杂度O(m)还是超,所以只能将复杂度降到O(m)以下。
我用了map容器,因为map的查找时间复杂度为O(logn)(底数为2)!这大大减少了查找的时间。

所谓的map,可以自动建立Key - value的一一对应关系。key 和 value可以是任意的类型。 根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1,024个记录,最多查找10次,1,048,576个记录,最多查找20次。 所以可以快速遍历所有记录。

map中的内容还可以自动排序,所以在查的时候,相当于在搜索一个二叉树(红黑树)。
使用map首先要加上头文件:#include< map >
map<int, int> p //两个int位可换成随意的类型。
map中相当于是 pair的集合。pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。例如pair<int,float> 或者 pair<ll,ll>等。pair实质上是一个结构体,其主要的两个成员变量是first和second,这两个变量可以直接使用。而pair.first是关键字,pair.second是和关键字相连的指向某数据的指针。

map的一些基本操作

1、构造、插入和全部删除

#include <iostream>
#include <map>

using namespace std;
typedef map<int,string> mapteac; //全局定义了mapteac来代替“map<int,string>”

int main()
{
    mapteac map1; //定义map1,前面的int为一个索引值(key),后面的string为指向string类的指针
    map<int,string> ::iterator t; //这里是构造了一个迭代器“t”
    map1.insert(pair<int,string>(1,"student1")); //将第一组数据插入,这里是讨论map究竟有没有排序
    map1.insert(pair<int,string>(3,"student3"));
    map1.insert(pair<int,string>(2,"student2"));
    for(t=map1.begin();t!=map1.end();t++)
        cout<<t->first<<"---"<<t->second<<endl; //证明map会自动根据建值排序
    map1.clear();//删除所有
    //map1.erase(Map.begin(),Map.end());//这个是通过迭代器t进行删除所有,和上面效果一样
    for(t=map1.begin();t!=map1.end();t++)
        cout<<t->first<<"---"<<t->second<<endl; //证明删除干净
    return 0;
}

提交结果:
在这里插入图片描述
2、加个查询find功能,在删除功能前面。

#include <iostream>
#include <map>

using namespace std;
typedef map<int,string> mapteac; //全局定义了mapteac来代替“map<int,string>”

int main()
{
    mapteac map1; //定义map1,前面的int为一个索引值(key),后面的string为指向string类的指针
    map<int,string> ::iterator t,q; //这里是构造了2个迭代器“t、q”
    map1.insert(pair<int,string>(1,"student1")); //将第一组数据插入,这里是讨论map究竟有没有排序
    map1.insert(pair<int,string>(3,"student3"));
    map1.insert(pair<int,string>(2,"student2"));
    for(t=map1.begin();t!=map1.end();t++)
        cout<<t->first<<"---"<<t->second<<endl;
    q=map1.find(2);  //map的find功能,通过查找key值,来找数据。
    if (q!=map1.end())
		cout<<q->first<<":"<<q->second<<endl;  //输出“2:student2”
    else
		cout<<"0"<<endl;
    map1.clear();//删除所有
    for(t=map1.begin();t!=map1.end();t++)
        cout<<t->first<<"---"<<t->second<<endl;
    return 0;
}

在这里插入图片描述
map还有很多好用的命令行:

begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
insert()插入元素
max_size()返回可以容纳的最大元素个数
size() 返回map中元素的个数
swap() 交换两个map
get_allocator() 返回map的配置器
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数

最初的题代码

#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<cstring>
using namespace std;
#define ll long long
const ll maxn=2*1e5+7;
ll b[maxn];
int main()
{
    map<ll,ll>mapn;
    memset(b,0,sizeof(b));
    ll m,n,a;
    ll num=0,sum=1;
    cin>>m>>n;
    for(ll i=1;i<=m;i++){
        cin>>a;
        if(mapn[a]==1) continue;//将a作为key值,1说明a在n范围内来过,
        else if(num<n){
                mapn[a]=1;//还没满,加上
                num++;
                b[num]=a;
        }
        else{
            mapn[a]=1;//把新来的书加上
            num++;
            b[num]=a;
            sum++;
            mapn[b[sum-1]]=0;  //前面加了,后面就要减,保持平衡。将前面的数给标记为0,说明在输出的时候不用输出,相当于把前面先输入的数kill掉
        }
    }
     cout<<num-sum+1<<endl; //总共要输出多少?别忘加上1哦,不然总会少一个。
     for(ll i=num;i>=sum;--i)
        cout<<b[i]<<" ";  //逆序输出
     cout<<endl;
    return 0;
}
发布了36 篇原创文章 · 获赞 1 · 访问量 1408

猜你喜欢

转载自blog.csdn.net/atnanajiang/article/details/103515194