数据结构 —— 键值对 map

目录

map的若干操作

1、emplace()

2、find(key)

3、count(key)

[4、lower_bound 和 upper_bound](#4、lower_bound 和 upper_bound)

5、erase()

6、empty()

7、降序的map

[计蒜客T3603 叫号系统](#计蒜客T3603 叫号系统)

题意:

解题思路:

Code:

[Leetcode1309 解码字母到整数映射](#Leetcode1309 解码字母到整数映射)

题意:

解题思路:

Code:

[Leetcode205 同构字符串](#Leetcode205 同构字符串)

题意:

解题思路:

Code:

[计蒜客T1271 完美K倍子数组](#计蒜客T1271 完美K倍子数组)

题意:

解题思路:

Code:


今天主要是map专题,一般map只是一个映射,在程序中大多是一个辅助的存在。不像前面的队列和栈,它们特殊的结构有一些衍生的算法思想。而map主要是熟悉它的操作,可以更方便的查找。其实原本今天的题目和map关系不是特别大,但是写到最后一题有很多相关的操作我都很少有用过,查了很多又改了好久才模拟出来。所以在最开始先盘点一下map常用的操作~


map的若干操作

map 键值对(key - value)

1、emplace()

功能 :原地构造键值对,效率更高。
示例:

cpp 复制代码
myMap.emplace(2, "banana"); // 直接构造,无需创建临时对象

2、find(key)

**功能:**通过键查找目标,找到了就返回相应迭代器,如果没找到返回end()。

示例:

cpp 复制代码
auto it = myMap.find(2);
if (it != myMap.end())
    cout << "找到键 " << it->first << ": " << it->second;
else cout << "未找到";

3、count(key)

**功能:**查找此键的个数,由于每个键在map中只能出现一次,所以只会返回1或0,可用于判断某个键是否存在。

示例:

cpp 复制代码
if (myMap.count(3) > 0)
    cout << "键3存在";

4、lower_bound 和 upper_bound

功能

  • lower_bound:返回第一个大于等于 key 的迭代器。
  • upper_bound(key):返回第一个大于 key 的迭代器。

示例:

cpp 复制代码
map<int, string> myMap = {{1, "a"}, {3, "c"}, {5, "e"}};
auto low = myMap.lower_bound(3); // 指向键3
auto up = myMap.upper_bound(3);  // 指向键5

5、erase()

功能:​​​​​​​删除指定元素。

示例:

cpp 复制代码
myMap.erase(key);           // 按键删除
myMap.erase(2);            // 删除键2
myMap.erase(myMap.begin()); // 删除第一个元素
myMap.erase(it);            // 按迭代器删除
myMap.erase(first, last);   // 删除区间 [first, last)

6、empty()

**功能:**判断此时是否为空,返回值为bool类型。

示例:

cpp 复制代码
if (myMap.empty()) cout << "容器为空";

7、降序的 map

**功能:**由于map会自动进行排序,系统默认是升序排序,其实还可以降序

示例:

cpp 复制代码
map<int, int, greater<int>> myMap;

myMap[3] = 30;
myMap[1] = 10;
myMap[4] = 40;
myMap[2] = 20;

// 输出结果会是 4,3,2,1
for (auto i : myMap)
    cout << i.first << ":" << i.second << endl;

常用的函数基本就这些了,其实map的主要功能是映射,这些函数是锦上添花。下面看几道题吧~

计蒜客T3603 叫号系统

链接:叫号系统 - 计蒜客

本题很好的考察了map的基本性质,比如排序,键、值的查找等。

题意:

给定1~7七种操作,根据操作执行。

  • op=1:将id和u录入系统;
  • op=2:找紧急程度最小的患者,输出id并删除.如果没有输出error;
  • op=3:找紧急程度最大的患者,输出id并删除.如果没有输出error;
  • op=4:将编号为id的病人紧急程度改为urg;
  • op=5:将紧急程度为urg的病人编号改为id;
  • op=6:查找标号为id的病人的urg并输出,如果没有输出error;
  • op=7:查找紧急程度为urg的病人的id并输出,如果没有输出error;

解题思路:

本题是个大模拟,要对键、值的查找比较熟悉,操作比较多需要认真一点。

接下来直接看代码吧。

Code:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fi first
#define se second
#define endl '\n'
const int N = 1e6+5;
map<int, int> mp;
int id,u;//Id和紧急程度
int op;
void solve()
{
	cin >> op;
	if(op==1)//将id和u录入系统
	{
		cin >> id >> u;
		mp[u]=id;//由于后面要找紧急程度的大小,所以按urg排序
	}
		if(op==2)//找紧急程度最小的患者,输出id并删除.如果没有输出error
	{
		if(mp.empty())
		{
			cout << "error" << endl;
			return ;
		}
		auto it = mp.begin();//迭代器类型索引用->
		cout << it->se << endl;
		mp.erase(it);
	}
	if(op==3)//找紧急程度最大的患者,输出id并删除.如果没有输出error
	{
		if(mp.empty())
		{
			cout << "error" << endl;
			return ;
		}
		auto it = --mp.end();//索引最后一个的时候用--end,end是最后一个的下一个
		cout << it->se << endl;
		mp.erase(it);
	}
	if(op==4)//将编号为id的病人紧急程度改为urg
	{
		cin >> id >> u;
		for(auto i:mp)
		{
			if(i.se==id)
			{
				auto it=mp.find(i.fi);
				mp.erase(it);
				mp[u]=id;
				break;
			}
		}
	}
	if(op==5)//将紧急程度为urg的病人编号改为id
	{
		cin >> id >> u;
		for(auto i:mp)
		{
			if(i.fi==u)
			{
				mp[u]=id;
				break;
			}
		}
	}
	if(op==6)//查找标号为id的病人的urg并输出,如果没有输出error	
	{
		cin >> id;
		int f=0;
		for(auto i:mp)
		{
			if(i.se==id)
			{
				f=1;
				cout << i.fi << endl;
				return ;
			}
		}
		if(!f) cout << "error" << endl;
	}
	if(op==7)//查找紧急程度为urg的病人的id并输出,如果没有输出error	
	{
		cin >> u;
		if(mp.find(u)==mp.end())
		{
			cout << "error" << endl;
			return ;
		}
		else
		{
			auto it=mp.find(u);
			cout << it->se << endl;
		}
	}
}
signed main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	cin >> t;
	while(t--) solve();
	return 0;
}

Leetcode1309 解码字母到整数映射

链接:1309. 解码字母到整数映射 - 力扣(LeetCode)

本题我直接用ASCII进行存值,但此题有点麻烦导致写的时候感觉有点乱

题意:

根据题中给的解码规则进行解码。

解题思路:

1~9的解码比较容易,10之后的有点麻烦,我是将数字和#分开判断,注意的是10之后一次是占据三个位置,注意下标不要超。

Code:

cpp 复制代码
class Solution {
public:
    string freqAlphabets(string s) 
    {
    	map<int, int> m;
    	string s1="";
    	for(int i=1; i<=26; i++) m[i]='a'+i-1;//创建键值对
        int i;
        for(i=0; i<s.size()-2; i++)//如果i在后两个i+2会超
        {
        	if(s[i+2]!='#') s1+=m[s[i]-'0'];
        	else
        	{
        		int num=(s[i]-'0')*10+s[i+1]-'0';
        		s1+=m[num];
        		i+=2;
        	}
        }
        
        if(i>s.size()-3)//单独处理在后两位的情况
            for(auto j=i; i<s.size(); i++) s1+=m[s[i]-'0'];
        
        return s1;
    }
};

Leetcode205 同构字符串

链接:205. 同构字符串 - 力扣(LeetCode)

题目其实还是比较简单,需要注意的点就是所有的键和值都是唯一的。

题意:

给定两个字符串看它们是否完全符合一定的映射规则。

解题思路:

按照所给字符串进行映射关系的建立和判断,如果前后冲突则为否。

Code:

cpp 复制代码
class Solution {
public:
    bool isIsomorphic(string a, string b) 
    {
        map<int, int> m;//这里用字符的ASCII码进行映射
        map<int, int> m1;
        for(int i=0; i<a.size(); i++)
        {
        	if(m[a[i]])//有值的话判断值
        	{
        		if(m[a[i]]!=b[i])
        			return 0;
        	}
        	else//没值先判断当前值是否被映射过
        	{
        		if(m1[b[i]]) return 0;
        		m[a[i]]=b[i],m1[i]=1;//没有就赋值,再标记一下表示被映射过
        	}
        }
        return 1;
    }
};

计蒜客T1271 完美K倍子数组

链接:完美K倍子数组 - 计蒜客

这题大思路是对的,就是情况没考虑周全。

题意:

给定一个长度为n的序列,找到一个子数组使得数组中的每个元素两两之和都是k的倍数。

解题思路:

由于数组中所有的数之和都是k的倍数,那首先很容易想到如果所有数都是它的倍数 那么就都可以了。由于是两两之和,所以如果K为偶数 的话,如果余数为k/2的数两两相加 那么也一定是k的倍数。如果前面的情况都不是,那么当两个数相加刚好等于k的倍数的时候那也可以,有点像昨天的某一道题。

Code:

cpp 复制代码
unordered_map<int, int> m;//余数->出现次数
void solve()
{
	cin >> n >> k;
	for(int i=1; i<=n; i++)
		cin >> a[i],m[a[i]%k]++;

	if(k%2==0)
	{
		//余数刚好是k/2
		/*
			例: 5 10
			    5 5 15 25 95
		*/
		for(int i=1; i<=n; i++) if(a[i]%k==k/2) num++;
		ans=max(ans,num);
		num=0;
	}
	
	for(int i=1; i<=n; i++) if(a[i]%k==0) num++;
	ans=max(ans,num),num=0;
	
	if(ans<2)
	{
        for(int i=1; i<=n; i++) 
        {
            int r = a[i]%k;//余数
            int c = (k-r)%k;//刚好和余数互补
            if(m[c]&&(m[c]>=2||(m[c]>= 1&&c!=r)))
            {
                ans=2;
                break;
            }
        }
    }
	if(ans<2)
		cout << -1;
	else cout << ans;
}

总体来说题目依旧比较高质量,虽然没什么算法,但也暴露出基本功的问题,不涉及算法的题还要修改好久,思路不够灵敏,继续加油吧!

相关推荐
DoraBigHead28 分钟前
小哆啦解题记——两数失踪事件
前端·算法·面试
不太可爱的大白28 分钟前
Mysql分片:一致性哈希算法
数据库·mysql·算法·哈希算法
Tiandaren4 小时前
Selenium 4 教程:自动化 WebDriver 管理与 Cookie 提取 || 用于解决chromedriver版本不匹配问题
selenium·测试工具·算法·自动化
岁忧5 小时前
(LeetCode 面试经典 150 题 ) 11. 盛最多水的容器 (贪心+双指针)
java·c++·算法·leetcode·面试·go
chao_7895 小时前
二分查找篇——搜索旋转排序数组【LeetCode】两次二分查找
开发语言·数据结构·python·算法·leetcode
秋说7 小时前
【PTA数据结构 | C语言版】一元多项式求导
c语言·数据结构·算法
Maybyy8 小时前
力扣61.旋转链表
算法·leetcode·链表
谭林杰9 小时前
B树和B+树
数据结构·b树
卡卡卡卡罗特10 小时前
每日mysql
数据结构·算法
chao_78910 小时前
二分查找篇——搜索旋转排序数组【LeetCode】一次二分查找
数据结构·python·算法·leetcode·二分查找