C++中map的介绍用法以及Gym题目:Two Sequences
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字(key),每个关键字只能在map中出现一次,第二个可能称为该关键字的值(value))的数据 处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的(转);
特点:增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key;
功能:
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
根据key值快速查找记录,查找的复杂度基本是Log(N)
头文件:#include<map>
数据的插入:
①:insert;
map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one"));
②:用insert函数插入value_type数据
map<int, string> mapStudent; mapStudent.insert(map<int, string>::value_type (1, "student_one"));
③:用数组方式插入数据
map<int, string> mapStudent; mapStudent[1] = "student_one"; mapStudent[2] = "student_two"; mapStudent[3] = "student_three"; map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) cout<<iter->first<<' '<<iter->second<<endl;
以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的,当然了第一种和第二种在效果上是完成一样的,用insert函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对应的值
Map的遍历
第一种:应用前向迭代器
第二种:应用反相迭代器,下放代码,正向就是rbegin改成begin,rend改成end;
int main() { map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); map<int, string>::reverse_iterator iter; for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++) cout<<iter->first<<" "<<iter->second<<endl; }
关于Map的sort的也从大牛的博客里copy来了解说,之前不会这种写法;
map中的元素是自动按Key升序排序,所以不能对map用sort函数;
这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int 型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过 不去,下面给出两个方法解决这个问题。
第一种:小于号重载,程序举例。
#include <iostream> #include <string> #include <map> using namespace std; typedef struct tagStudentinfo { int niD; string strName; bool operator < (tagStudentinfo const& _A) const { //这个函数指定排序策略,按niD排序,如果niD相等的话,按strName排序 if(niD < _A.niD) return true; if(niD == _A.niD) return strName.compare(_A.strName) < 0; return false; } }Studentinfo, *PStudentinfo; //学生信息 int main() { int nSize; //用学生信息映射分数 map<Studentinfo, int>mapStudent; map<Studentinfo, int>::iterator iter; Studentinfo studentinfo; studentinfo.niD = 1; studentinfo.strName = "student_one"; mapStudent.insert(pair<Studentinfo, int>(studentinfo, 90)); studentinfo.niD = 2; studentinfo.strName = "student_two"; mapStudent.insert(pair<Studentinfo, int>(studentinfo, 80)); for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++) cout<<iter->first.niD<<' '<<iter->first.strName<<' '<<iter->second<<endl; return 0; }
第二种:仿函数的应用,这个时候结构体中没有直接的小于号重载,程序说明
/第二种:仿函数的应用,这个时候结构体中没有直接的小于号重载,程序说明 #include <iostream> #include <map> #include <string> using namespace std; typedef struct tagStudentinfo { int niD; string strName; }Studentinfo, *PStudentinfo; //学生信息 class sort { public: bool operator() (Studentinfo const &_A, Studentinfo const &_B) const { if(_A.niD < _B.niD) return true; if(_A.niD == _B.niD) return _A.strName.compare(_B.strName) < 0; return false; } }; int main() { //用学生信息映射分数 map<Studentinfo, int, sort>mapStudent; map<Studentinfo, int>::iterator iter; Studentinfo studentinfo; studentinfo.niD = 1; studentinfo.strName = "student_one"; mapStudent.insert(pair<Studentinfo, int>(studentinfo, 90)); studentinfo.niD = 2; studentinfo.strName = "student_two"; mapStudent.insert(pair<Studentinfo, int>(studentinfo, 80)); for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++) cout<<iter->first.niD<<' '<<iter->first.strName<<' '<<iter->second<<endl; }
还有一些Map的函数就偷懒直接列下来了;
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map map中的swap不是一个容器中的元素交换,而是两个容器所有元素的交换。
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数
然后,今天写了一道有用到map的题,其实是用了map超级高效易懂;
以前写题目,遇到判断一个数是否出现过,都用flag[maxen]来进行存状态,但这只适用于数据范围较小的情况,若数据范围到1e9,那就GG了。今天在提示下想到用map,
建一个<long long,int>的map,first 表示该数是否出现过,int 代表出现几次;
不多说上题目;
Gym Two Sequences
You are given two sequences of integers AA and BB, and an integer kk.
Two sequences are equal if it is possible to rearrange one of the sequences such that each element in the sequence is equal to the corresponding element from the other sequence.
You can select one of the elements in sequence AA, and add to it any integer from the range [−k,k][−k,k]. Is it possible to make the two sequences equal by doing the specified operation exactly once?
Input
The first line of input contains a single integer TT, the number of test cases.
The first line of each case contains two space-separated integers nn and kk (1≤n≤1051≤n≤105)(1≤k≤1091≤k≤109), the length of each sequence and the number kk specified in the problem statement.
The next line contains nn space-separated integers (1≤Ai≤1091≤Ai≤109), the elements in sequence AA.
The next line contains nn space-separated integers (1≤Bi≤1091≤Bi≤109), the elements in sequence BB.
Output
For each test case, output a single line with YES if it is possible to make the two sequences equal in a single operation. Otherwise output NO.
Example
3
3 2
1 2 3
3 2 1
4 2
1 9 1 1
6 1 1 1
2 4
1 5
1 1
YES
NO
YES
题意:开始理解错了,debug到崩溃,半夜才懂得题意是给两个序列A、B,若将A、B中某一序列排序后与另一序列每个对应元素相等,就输出YES(其实意思就是俩序列完全相等咯),或者是如果B序列里面有一个数
与A中对应不相等,那如果给A中对应元素加上范围[-k,k]范围内的某个数可以令A[i]=B[i],且只能改一次,那也输出YES,否则NO;
#include <stdio.h> #include <string.h> #include <string> #include <iostream> #include <algorithm> #include <cmath> #include <map> const int maxen=100100; using namespace std; typedef long long ll; ll a[maxen],b[maxen]; map<ll,int>mp; int main(void){ int T,n,k; scanf("%d",&T); while(T--){ scanf("%d %d",&n,&k); mp.clear(); for(int i=0;i<n;++i){ scanf("%lld",&a[i]); mp[a[i]]++; } int pos,count=0,flag=1; for(int i=0;i<n;++i){ scanf("%lld",&b[i]); } for(int i=0;i<n;++i){ if(mp[b[i]]){ --mp[b[i]]; if(mp[b[i]]==0){ mp.erase(b[i]); } } } int t=mp.size(); if(t==0){ printf("YES\n"); } else if(t==2){ map<ll,int>::iterator start=mp.begin(); ll pos1=start->first; \\指向ll的,即键值; start++; \\指向下一个 ll pos2=start->first; if(abs(pos1-pos2)<=k){ printf("YES\n"); } else{ printf("NO\n"); } } else{ printf("NO\n"); } } return 0; }
里面有一点小笔记,map的一些函数也灵活用在里面,map真是伟大啊!
看网上都没有这道题的题解,可能是因为太简单了吧,但是菜鸡也从里面学了一些东西,加油!O(∩_∩)O
一只呆在图书馆的猴猴
2019.3.12