什么是set和map
学过数据结构的直接跳过。
set在C++中称为集合,里面存放了一系列数据(这些数据一般是不重复的)。
这和vector有啥区别?区别就是,我们可以在O(1)时间复杂度内就能知道这个数据内包不包含某个值。怎么实现的你别管,你只需要知道有这么个功能就行。
而map在set的基础上更近一步,可以以set里面的值作为下标来存放数据,这样的话通过想要的下标来访问数据就可以在O(1)时间复杂度内完成。
这么说起来可能有点抽象,那我就用最简单说法:这个数组的下标不再是冷冰冰的01234,而是想定义成啥样就定义成啥样。比如说我想记录动物园里面的小动物,有3只鸟,5只猪,13只狗就可以写成:
animal["bird"] = 3;
animal["pig"] = 5;
animal["dog"] = 13;
C++内置的set和map
在C++里有多种set和多种map,分别叫:
set、map、multiset、multimap、unordered_set、unordered_map、unordered_multiset、unordered_multimap等等,但这些不重要,重要的是你只需要使用unordered_set和unordered_map就行了。
unordered代表无序,传进去的set和map不会多一个排序步骤,所以效率更高。
当然,使用set和map也能完成题目,单词还更好记,只不过效率上会差一点。
#include <unordered_set>
#include <unordered_map>
set的使用方法例:
创建一个新set:
unordered_set<int> st;
创建一个新set并初始就填入一定的数据:
// 因为是不重复的,所以虽然数组里有两个5,但实际上st里只会放一个
unordered_set<int> st{1, 3, 5, 5, 2};
插入数据:
st.insert(7);
删除数据:
st.erase(5);
寻找set里是否存在某一个数据:
unordered_set<int>::iterator iter = st.find(3);
find函数返回的是一个迭代器,如果找到了该数据就返回该数据的迭代器,如果找不到该数据就返回end()迭代器。
当然一般而言我们不会再专门用一个迭代器去接收.find(),常用的使用方法是这样的:
if (st.find(3) != st.end()) {
// 返回的不是end(),说明找到了该数据
}
else {
// 返回的是end(),说明找不到该数据
}
既然有迭代器,那自然也就有遍历了
for (auto iter = st.begin(); iter != st.end(); iter++) {
cout << *iter;
}
不用迭代器遍历也是可以的
for (int num : st) {
cout << num;
}
map的使用方法例
map和set的使用方法很像。顺带一提,map底层数据的存储模式和pair<>一样。需要输入两个数据类型,第一个是key的类型,第二个是value的类型
unordered_map<string, int> animal; // 创建
animal.insert({"cat", 3}); // 插入
animal.erase("cat"); // 删除
if (animal.find("cat") != animal.end()) { // 寻找特定值
}
else {
}
因为存储模式和pair<>一样,所以遍历的时候接收的值就是pair<>
for (auto iter = animal.begin(); iter != animal.end(); iter++) {
cout << (*iter).first;
cout << (*iter).second;
}
不过迭代器看着很麻烦,建议用另一种遍历方法
for (auto pr : animal) {
cout << pr.first;
cout << pr.second;
}
相较于set,map还有一些额外用法
map可以像使用数组一样,将key值当数组下标来访问值。
cout << animal["cat"];
当你需要给map里添加内容的时候,并不一定需要用insert,直接使用中括号就可以了。
animal["dog"] = 3; // 此时map中没有dog,会自动新建一个dog来存储3
animal["dog"] = 4; // 此时map中已经有dog了,会将3变成4
如果value的值是int型,那么当我们在计数的时候甚至可以直接使用++。如果key值不存在会直接创建一个key值进入map中。
animal["mouse"]++; // 此时map中没有mouse,会自动创建一个mouse,value为0,++之后就变成1了
哈希表题目总结
像有些题目属于一眼哈希,多思考一秒钟都是对哈希表的不尊重的:
除了这种一眼哈希的题目之外,还有遇到如下情况可以使用哈希表:
当需要找到一个数组中两数之和等于某特定数的时候。
另外,先前说了,在一些前缀和的问题之中也可以使用哈希表。
比如说题目是找到一串数组是否存在一串子序列,使子序列之和等于某特定值的时候,就可以转换为找到某两个前缀,使它们之差等于某特定值,和上面的两数之和那道题就非常像了。