😲示例
主要使用map和set, 如果是键值对结构就使用map, 如果不是键值对结构但是需要去重, 就使用set
unordered_set是C++标准库中的一个容器,用于存储唯一的元素集合,所以需要去重的数据可以用它来存, 元素的存储顺序是无序的。下面是unordered_set的基本用法、常见函数和遍历方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <unordered_set>
std::unordered_set<int> mySet; std::unordered_set<int> mySet = {1, 2, 3}; std::vector<int> vec = {1, 2, 3, 4, 5}; std::unordered_set<int> mySet(vec.begin(), vec.end()); std::unordered_set<int> mySet1 = {1, 2, 3}; std::unordered_set<int> mySet2(mySet1);
mySet.insert(4); mySet.insert({5, 6, 7});
mySet.erase(3); mySet.clear();
auto it = mySet.find(2);
if (it != mySet.end()) { } else { }
if (mySet.count(3) > 0) { } else { }
int size = mySet.size();
for (auto it = mySet.begin(); it != mySet.end(); ++it) { }
for (const auto& element : mySet) { }
|
unordered_map的用法和常用函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include <iostream> #include <unordered_map>
int main() { std::unordered_map<int, std::string> myMap;
myMap.insert({1, "apple"}); myMap[2,"orange"];
std::cout << "Value at key 2: " << myMap[2] << std::endl;
if (myMap.count(2) > 0) { std::cout << "Key 2 exists" << std::endl; }
auto it = myMap.find(2); if (it != myMap.end()) { std::cout << "Key 2 found. Value: " << it->second << std::endl; } else { std::cout << "Key 2 not found." << std::endl; }
myMap[1] = "grape";
myMap.erase(2);
for (const auto& pair : myMap) { std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl; }
return 0; }
|
注意使用了两种查找auto, auto it = myMap.find(2);
返回的是迭代器指针, 如果需要成员变量需要使用->
, 而const auto& pair : myMap
使用了迭代器的引用类型, 使用指针初始化引用类型, 引用类型的使用和原变量一样, 直接使用.
🤔一些疑问解答
const auto& pair : myMap
中必须加const
吗?
在遍历unordered_map
时,使用const auto& pair : myMap
是一种常见的做法,但并不是必须的
使用const auto&
可以确保你不会意外地修改unordered_map
中的元素。这是一种安全的做法
如果需要再遍历的过程中修改或删除一些值, 那么可以使用auto&
而不是const auto&
为什么有的哈希表题目并没有用哈希表来做而是用数组?
如果题目中确实需要查每个元素, 但是元素的取值范围并不大, 而且索引可以直接算出来不需要遍历, 那么就可以直接用数组, 比如力扣题目242
💪力扣刷题
242. 有效的字母异位词
力扣传送门
这个需要一个哈希表记录所有字母的出现次数, 但是由于题目中只出现26个字母, 所以也可以直接使用数组记录字母出现次数
如果s中出现字母, 则再记录表中+1, 如果t表中出现字母, 则再记录表中-1, 最后只需要记录表中有没有非0元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public: bool isAnagram(string s, string t) { int letter[26] = {0}; for(int i=0; i<s.size(); i++) letter[s[i]-'a']++; for(int i=0; i<t.size(); i++) letter[t[i]-'a']--; for(int i=0; i<26; i++) if(letter[i]!=0) return false; return true; } };
|
349. 两个数组的交集
力扣传送门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> data(nums1.begin(),nums1.end()); unordered_set<int> rs; int len = nums2.size(); for(int i=0; i<len; i++){ if(data.find(nums2[i])!=data.end()) rs.insert(nums2[i]); } return vector<int>(rs.begin(),rs.end()); } };
|
202. 快乐数
力扣传送门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public: bool isHappy(int n) { int new_n=n, sum; unordered_set<int> sums; while(new_n!=1){ int k; sum = 0; while(new_n!=0){ k = new_n%10; sum+=k*k; new_n/=10; } if(sums.find(sum)!=sums.end()) return false; else sums.insert(sum); new_n = sum; } return true; } };
|
1. 两数之和
力扣传送门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> rs(2); unordered_map<int,int> my_map; int len = nums.size(); for(int i=0; i<len; i++) my_map[nums[i]] = i; for(int i=0; i<len; i++){ auto it = my_map.find(target-nums[i]); if(it!=my_map.end() && it->second!=i){ rs[0] = i; rs[1] = it->second; break; } } return rs;; } };
|
454. 四数相加 II
力扣传送门
先统计前两个数组的所有和, 用map, 键是和, 值是和出现的次数
再统计后两个数组的所有和, 不用新建map, 直接查之前的那个map里有没有相反数, 有的话结果就加上对应的情况数目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { unordered_map<int,int> my_map; for(int i:nums1){ for(int j:nums2){ my_map[i+j]++; } } int count = 0; for(int i:nums3){ for(int j:nums4){ if(my_map.find(0-i-j)!=my_map.end()){ count+=my_map[0-i-j]; } } } return count; } };
|
383. 赎金信
力扣传送门
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public: bool canConstruct(string ransomNote, string magazine) { int letter[26] = {0}; for(char i:magazine) letter[i-'a']++; for(char i:ransomNote) letter[i-'a']--; for(int i:letter) if(i<0) return false; return true; } };
|
15. 三数之和
力扣传送门