【PAT】第六章 C++标准模板库 -map

6.4 map的常用函数

将任意基本类型(包括STL)映射到任意基本类型(包括STL)上,形成有序键值对<key,value>。键唯一。

实现:红黑树。

头文件:#include <map>using namespace std;

6.4.1 map的定义

map<typename1,typename2> mp;
// example
map<int,vector<string> > mp;
map<set<string>,int> mp;

【注】字符串必须使用string,不能使用字符数组。

6.4.2 map内元素的访问

1. 下标访问
map<char,int> mp;
printf("%d",mp['c']);
2. 迭代器访问
map<typename1,typename2>::iterator it;

其中,it->first访问键,it->second访问值。

6.4.3 map常用函数

1. 查找元素
- find()

find(key)返回键为key的映射的迭代器,时间复杂度为O(logn)

如果key不在mp中,则find返回迭代器 mp.end()

map<int,int>::iterator it=mp.find(2);
if(it!=mp.end())
{
    cout<<"find success!"<<endl;
}
else
{
	cout<<"find failed!"<<endl;
}
- count()

count("key")返回元素出现的次数,缺点是无法定位元素出现的位置。由于map是一对一的映射,所以count("key")的返回值要么是1,要么是0。

map<string,int> my_map;
my_map["first"]=1;
cout<<my_map.count("first")<<endl;    //输出1;
2. 删除元素
- erase()
  • 删除单个元素
    根据迭代器删除元素,时间复杂度为O(1)
map<int,string>::iterator it;  
it=mp.find(1);  
mp.erase(it);  
  • 删除单个元素
    根据删除元素,时间复杂度为O(logn)
 mp.erase(key)
  • 删除一个区间内的元素
    根据迭代器删除区间元素。删除[first,last)区间的所有元素。时间复杂度为O(last-first)
 mp.erase(first,last)
  • 清空整个map
mp.erase( mp.begin(), mp.end() );
3. 获取键值对的数量
- size()

获得map中键值对的对数。复杂度为O(1)

int cnt=mp.size();
4. 清空
- clear()

清空map。复杂度为O(n)

mp.clear();
- erase()

通过erase()清空map,复杂度为O(n)

mp.erase( mp.begin(), mp.end() );

6.4.4 map的常见用途

  • 建立字符与整数之间的映射(或者其他数据类型之间的映射)。
  • 判断大整数或其他类型数据是否存在,作为bool数组

6.4.5 例题

【例】1054 The Dominant Color

ATTENTION

  • 看题的时候奇怪有两种判断:出现最多的或者超过半数的。
    看了柳神的思路后发现这两种判断都可以。所以可以在更新了出现次数后直接判断是否大于半数,大于就直接输出,结束程序。
  • 其实不用判断像素是否已经在mp中。map代表的是一种映射关系,但实则此题中存储的就是两个int值,而在int值在这里貌似默认初始值为0。但这么写有风险,还是做判断叭。
/*map的使用太生疏了!!!
  find() 迭代器 ......
  练练练!!! 
*/
#include <cstdio>
#include <map>
using namespace std;

int n,m;
map<int,int> mp; 	// <像素点,数量>

int main()
{
	scanf("%d %d",&m,&n);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			int tmp;
			scanf("%d",&tmp);
			map<int,int>::iterator it=mp.find(tmp);
			if(it==mp.end())
				mp[tmp]=1;
			else
				it->second=it->second+1; 	//mp[tmp]+=1;
		}
	}
	int max=0,ans=0;
	for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
	{
		if(it->second>max)
		{
			max=it->second;
			ans=it->first;
		}
	}
	printf("%d",ans);
	return 0;
}

【例】A1071 Speech Patterns (25 分)

preference n. 偏爱,倾向;优先权
synonym n. 同义词;同义字
cop n. 警察
narrow down 缩小;限制;减少;变窄
validate vt. 证实,验证;确认;使生效
avatar n.化身(印度教和佛教中化作人形或兽形的神); (尤指电脑游戏或聊天室中代表使用者的)化身
alphanumerical adj. 字母数字混合编制的
lexicographically 字典序

ATTENTION

  • 不是难题,单纯考STL运用。
  • 注意大小写转换
  • 注意curclear
  • mapset还不够熟练。本来想用set的,因为不用自己排序了,结果不会用= =。后来发现还是用map方便,毕竟map可以把stringcnt映射起来。
#include <iostream>
#include <map>
#include <string>
using namespace std;

string str;
map<string,int> st;

int main()
{
	getline(cin,str);
	int idx=0;
	string cur="";
	while(idx<str.size())
	{
		if(str[idx]>='A'&&str[idx]<='Z')
			str[idx]=str[idx]-'A'+'a';
		while(str[idx]>='0'&&str[idx]<='9'||str[idx]>='a'&&str[idx]<='z')
		{
			cur+=str[idx]; 	//string+char?
			idx++;
			if(str[idx]>='A'&&str[idx]<='Z')
				str[idx]=str[idx]-'A'+'a';
		}
		if(st.find(cur)==st.end())
			st[cur]=1;
		else
			st[cur]++;
		cur=""; 	//注意这里要clear
		if(!(str[idx]>='0'&&str[idx]<='9'||str[idx]>='a'&&str[idx]<='z'))
		{
			while((!(str[idx]>='0'&&str[idx]<='9'||str[idx]>='a'&&str[idx]<='z'))&&idx<str.size())
			{
				idx++;
				if(str[idx]>='A'&&str[idx]<='Z')
					str[idx]=str[idx]-'A'+'a';
			}	
		}
	}
	int cnt=0;string ans;
	for(map<string,int>::iterator it=st.begin();it!=st.end();it++)
	{
		if(it->second>cnt)
		{
			cnt=it->second;
			ans=it->first;
		}
		else if(it->second==cnt)
		{
			if(it->first<ans)
				ans=it->first;
		}
	}
	cout<<ans<<" "<<cnt;
	return 0;
}

【例】A1149 Dangerous Goods Packaging (25 分)

incompatible adj. 不相容的;矛盾的;不能同时成立的

ATTENTION

  • map<int,vector<int> > mp
  • 主要是不熟练这个用法,写这道题的时候都没想起来,绕了个弯子。
  • 说来也难受,和平常单纯刷题比起来,模拟的时候真的会出现各种奇奇怪怪的错误…

原来版本:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> p[100010];
int m,n,k;
int goods[100010]={0};

int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		p[a].push_back(b);
		p[b].push_back(a);
	}
	for(int i=0;i<m;i++)
	{
		cin>>k;
		fill(goods,goods+100010,0);
		bool flag=true;
		for(int j=0;j<k;j++)
		{
			int a;
			cin>>a;
			if(goods[a]==0)
			{
				goods[a]=1;
				for(vector<int>::iterator it=p[a].begin();it!=p[a].end();it++)
				{
					goods[*it]=1;		
				}		
			}
			else
			{
				flag=false;
				//break; 	//不能break,会导致数还没读完就退出 
			}
		}
		if(flag) cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}

后来版本:

#include <iostream>
#include <map>
#include <vector>
using namespace std;

int n,m,k;
map<int,vector<int> > mp;

int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		mp[a].push_back(b);
		mp[b].push_back(a);
	}
	while(m--)
	{
		bool flag=true;
		int vis[100010]={0};
		cin>>k;
		for(int i=0;i<k;i++)
		{
			int p;
			cin>>p;
			vis[p]=1;
			for(int j=0;j<mp[p].size();j++)
			{
				if(vis[mp[p][j]]==1)
				{
					flag=false;
					break;
				}
			}
		}
		if(flag) cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值