map浅浅的应用

        简单的桶排序的基本思路是用一个bool数组,下标是数字,存的内容是存在/不存在,通过一次线性存储和一次线性遍历就可以做到降重和排序。但是这个线性次数最后取决于数据范围,如果数字范围是1e9甚至要做1e9次的查询。所以就考虑到使用map。

        map是一种散列的数据结构,由键和值组成的,既可以构造int和int之间的映射(例如数字大小和出现次数的映射),也可以构造任何自定义类型之间的映射。支持快速查找,删除和操作,而且有有序性。map类型需要比较,如果是自定义类型要重载小于号。

举几个例子:

第一个例子是判断一个数组是否存在一个子区间,使得奇数和等于偶数和

Problem - 1915E - Codeforces

#include <bits/stdc++.h>
using namespace std;
map<long long,bool> flag;
long long a[210000],n;
bool check()
{
	long long sum1=0,sum2=0;
	for(int i=1;i<=n;i++)
	{
		if(i%2) sum1+=a[i];
		else sum2+=a[i];
		
		if(sum1==sum2||flag[sum1-sum2])
		{
			return 1;
		}
		
		flag[sum1-sum2]=1;
	}
	return 0;
}
int main()
{
	
	int t;cin>>t;
	while(t--)
	{
		flag.clear();
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
		}
		if(check())
		cout<<"YES"<<endl;
		else
		cout<<"NO"<<endl;
	}
	return 0;
	
}

这个题通过前缀和计算,到最后只需要判断oddsum[i]-oddsum[j]==evensum[i]-evensum[j];

即是否存在一对oddsum[i]-evensum[i]的值相等,如果正常计算时间会超限

头文件就是<map>,定义了一个longlong数字到bool类的映射。我们线性遍历每个sum1-sum2;

把每个sum1-sum2作为唯一键,出现一次就value++;

如果value等于2就是yes,如果没有2就是yes;

这样线性寻找很方便。

在使用map的时候,可以直接使用mp[flag]++来建立一个映射,这是因为map支持下标操作。map的下标操作符[]可以用来访问或设置map中的元素。如果map中不存在键为flag的元素,则下标操作符会自动创建一个新的键值对,其中键为flag,值为0。然后,下标操作符会返回该键值对的引用,因此你可以直接对值进行修改。

一些操作,

遍历

for(auto &i:mp)cout<<i.first<<" "<<i.second<<endl;

第二个例子

在一堆字符串中,能否找到两个字符串相加得到另一个字符串(可以重复)

Problem - 1703D - Codeforces

#include <iostream>
#include <map>
const int maxn=1e5+10;
using namespace std;
string str[maxn];
void solve(){
	map<string,int> mp;
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		cin>>str[i];
		mp[str[i]]=1;
	}
	
	for(int i=1;i<=n;i++){
		int flag=0;
		for(int j=1;j<str[i].length();j++){
			string str1=str[i].substr(0,j);
			string str2=str[i].substr(j);
			flag|=(mp[str1]&&mp[str2]);//如果str1.str2都出现在了这个数组里,说明有字串。 
		}
		cout<<flag; 
	}
	cout<<endl;
}
int main()
{
	int p;cin>>p;
	for(int i=0;i<p;i++)
	{
		solve();
	}
	return 0;
}

这道题的基本思路来源于题干:字符串的长度不超过8,所以我们把问题转化为,能否找到一个分割使得两个字串都在这个字符串数组里。

这道题构建了一个string到int的映射,即这个字符串在数组内部出现了多少次。

也是桶排序的思想。

flag|=(a&&b)是一个小技巧,如果ab两个都满足那么falg就是1.

还有找字串substtr;

第三个例子

是集训期间的一道题。
彦卿希望能花光预算(月底好跟将军蹭饭吃),因此每个购买方案都需要花光预算。一个购买方案只包括要买的两种宝剑(购买第1,3把宝剑和购买第3,1把宝剑视为同一种方案)。

输入描述

第一行包括两个数字n(1≤n≤2e6), t(1≤t≤2e9),分别代表宝剑的数目和预算。
第二行包括n个数字ai​( 1≤i≤n ) ( ∣ai​∣≤2e9),代表第 i 把宝剑的单价。

输出描述

输出一个数字,表示彦卿可选的购买方案。

用例输入 1 

2 14233
387 6729

用例输出 1 

0

用例输入 2 

3 14232
387 6729 387

用例输出 2 

2

提示

样例1中,(387+6729)∗2=14232=14233,因此没有一种购买方案能满足彦卿的要求。故输出0.
样例2中,有(1,2),(2,3)两种方案可以满足彦卿的要求,故输出2.
注意宝剑的单价可能为负数(你可以理解为代言费)。

#include <iostream>
#include <map>
using namespace std;
const int maxn=2e6+10;
long long int arr[maxn];
long long int cnt[30];
int main()
{
	map<long long int,long long int>mp;
	long long int n,t;cin>>n>>t;
	for(int i=1;i<=n;i++) cin>>arr[i];
	long long int ans=0;
	for(int i=1;i<=n;i++){
		if(mp[t-arr[i]*2]) ans+=mp[t-arr[i]*2];
		mp[arr[i]*2]++;
	}//找的是一对,遍历的左端时候是存储,遍历右端的时候是增加; 
	cout<<ans<<endl;
	return 0;
}

这个题特殊点在于数据范围很大而且数据个数较多。如果直接开数组会爆炸。

如果构造一个map<long long int ,long long int>即这个数据出现了多少次,可以减少数据个数,节省存储空间。

这道题跟上面两个类似,也是找有没有一对数据满足一个条件,即(a+b)*2==t;

处理的也很巧妙,左面存储:把t-2a存进去,右边检验是不是有对应的2b.如果有说明有一种方案

总结一下,map可以很方便的处理两个数据满足的同一确定条件,如相等,相加为定值等问题。

通过map可以线性操作就解决。而且map极大节省了空间,且可以构造不同数据类型之间的映射,肥肠好用。

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值