本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1. 杂项
定义一个哈希表
unordered_map<typenameA,typenameB> hash; // key value
常用函数
//增加元素
hash[key] = value;
//删除元素
hash.erase(key); // 如果没有找到会返回0
//修改元素
hash[key] = new value;
//查找元素
hash.find(key); // 常用hash.find(key) == hash.end()来判断key值是否存在
hash.count(key) // 该函数:用以统计key值在unordered_map中出现的次数。c++ unordered_map不允许有重复的key。因此,如果key存在,则count返回1,如果不存在,则count返回0
//————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
//遍历元素
for (auto it = mp.begin(); it != mp.end(); ++it) //遍历的方法
{
cout <<"key为:" << it->first << " value为:";
for (int i = 0; i < it->second.size(); i++)
{
cout << (it->second)[i]<<' '; //这边的value是vector<string>类型的,不能直接用cout打印
//,所以要循环一个一个字符串打印出来
}
cout << endl;
}
2. emplace_back 函数解析
也是添加元素的函数,只不过和vector容器的push_back()的区别在于: push_back()方法要调用构造函数和复制构造函数,这也就代表着要先构造一个临时对象,然后把临时的copy构造函数拷贝或者移动到容器最后面。而emplace_back()在实现时,则是直接在容器的尾部创建这个元素,省去了拷贝或移动元素的过程。
vector<pair<int, int>> ret;
ret.push_back(1,1)//会报错,因为没有构造一个临时对象
ret.push_back(pair(1,1))//不会报错,因为构成了一个pair对象
ret.emplace_back(1,1)//不会报错,因为直接在容器的尾部创建对象
vector<vector<int>> ans;
int lastcol = INT_MIN;
for (const auto& [col, row, value]: nodes) {
if (col != lastcol) {
lastcol = col;
ans.emplace_back();//这里的emplace_back()直接在ans的尾部创建一个类型为vector<int>的空对象,如果省去这一行,后面的ans.back()会是一个空指针而报错。
}
ans.back().emplace_back(value);
}
3.哈希表的应用总结
3.1 力扣49 (字母异位词)
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 ==字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。== 输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
这边的键值对采用的是:由于互为字母异位词的两个字符串包含的字母相同,因此对两个字符串分别进行排序之后得到的字符串一定是相同的,故可以将排序之后的字符串作为哈希表的键。
vector<string> strs;
unordered_map<string, vector<string>> mp;
strs.push_back("eat");
strs.push_back("tea");
strs.push_back("tan");
strs.push_back("ate");
strs.push_back("nat");
strs.push_back("bat");
for (string& str : strs) { //确定好排序好的key!
string key = str;
sort(key.begin(), key.end());
mp[key].emplace_back(str); //这边插入的key和value相对应!
}
for (auto it = mp.begin(); it != mp.end(); ++it) //遍历的方法
{
cout <<"key为:" << it->first << " value为:";
for (int i = 0; i < it->second.size(); i++)
{
cout << (it->second)[i]<<' '; //这边的value是vector<string>类型的,不能直接用cout打印
//,所以要循环一个一个字符串打印出来
}
cout << endl;
}
//排好序的结果如下图,最后按照下面的这个图 按照顺序放到 ans 里面就行了
vector<vector<string>> ans;
for (auto it = mp.begin(); it != mp.end(); ++it) {
ans.emplace_back(it->second);
}
3.2 力扣49 法二 另一种键值对方式
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 ==字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。== 输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
由于互为字母异位词的两个字符串包含的字母相同,因此两个字符串中的相同字母出现的次数一定是相同的,故可以将每个字母出现的次数使用字符串表示,作为哈希表的键。 由于字符串只包含小写字母,因此对于每个字符串,可以使用长度为 2626 的数组记录每个字母出现的次数。需要注意的是,在使用数组作为哈希表的键时,不同语言的支持程度不同,因此不同语言的实现方式也不同。
vector<string> strs;
strs.push_back("eat");
strs.push_back("tea");
strs.push_back("tan");
strs.push_back("ate");
strs.push_back("nat");
strs.push_back("bat");
vector<vector<string>> res;
map<string, vector<string>> map;
// 统计string的各字母频次,以频次为key直接加入队列
for (auto s : strs) {
string st = string(26, '0'); //先是弄成26个字母都是零
for (auto c : s) ++st[c - 'a']; //将有出现的字母对应的位置加 1
map[st].emplace_back(s); //放到键值对当中, st作为key是这个26个数 s作为value是正常的字符串
}
for (auto e : map) res.emplace_back(e.second); //放到 vector 当中
//遍历方法
for (auto it = map.begin(); it != map.end(); ++it) //遍历的方法
{
cout << "key为:" << it->first << " value为:";
for (int i = 0; i < it->second.size(); i++)
{
cout << (it->second)[i] << ' '; //这边的value是vector<string>类型的,不能直接用cout打印
//,所以要循环一个一个字符串打印出来
}
cout << endl;
}
3.3 力扣451 哈希表的深入理解
给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。 返回 已排序的字符串 。如果有多个答案,返回其中任何一个。
输入: s = "tree" 输出: "eert" 解释: 'e'出现两次,'r'和't'都只出现一次。 因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。 ==直接先按照字母出现的频率来创建哈希表,这样key为字母值,value为他出现的频率。 然后将其放到vector当中按照value的大小进行从大到小排序。 最后放到string reuslt当中即可。==
string s;
s = "baafAAag";
unordered_map<char, int> mp; //哈希表这样创建的,key是char类型,value是int类型
int length = s.length();
for (auto& ch : s) {
mp[ch]++; //这里怎么放key和value的!!很巧妙
}
//遍历哈希表元素
for (auto it = mp.begin(); it != mp.end(); ++it) //遍历的方法
{
cout << "key为:" << it->first << " value为:";
cout << it->second;
cout << endl;
}
vector <pair<char, int>> temp; //创建内容格式和哈希表一致的vector容器,将哈希表的内容放到vector容器当中
for (auto& it : mp) {
temp.push_back(it); //格式一样,直接push_back
}
for (int i = 0; i < temp.size(); i++) {
cout << temp[i].first << " ";
cout << temp[i].second << endl;
}
for (int i = 0; i < temp.size() - 1; ++i) { //利用冒泡排序根据value的大小进行排序
for (int j = 0; j < temp.size() - i - 1; ++j) {
if (temp[j].second < temp[j+1].second)
{
pair<char, int> tempp;
tempp = temp[j];
temp[j ] = temp[j+1];
temp[j+1] = tempp;
}
}
}
for (int i = 0; i < temp.size(); i++) {
cout << temp[i].first << " ";
cout << temp[i].second << endl;
}
string result;
for (auto& it : temp) {
result = result.append(it.second, it.first); //最后按照顺序放到string reuslt当中即可
}
cout << result << endl;