哈希表
理论基础 ——
哈希表更属于一种思想,即快速判断一个元素是不是在表里,本质上属于使用空间换时间,基于这种思想,衍生出了用法与特殊的容器
这种思想可以抽象为一个函数,通过把key值编码成hashcode,就可以用hashcode表示key值;如果待存入的key值大于表的大小,那么可以通过取表大小模的方式,就可使所有元素在表中都有映射 。
这就导致了哈希碰撞问题的出现:如果两个不同元素,映射到了同一位置,应该怎么办?
解决方法一般而言有两种,拉链法和线性探测法
拉链法的思想很简单,就是把表定义为一个一个的链表,如果映射到同一位置,直接存储在next地址里,就像个拉链一样,一直往下顺;
另一种方法是线性探测法,此时需要保证标的大小,大于数据的大小,依靠表中必然会出现的空位置来解决碰撞问题
在我的印象里,哈希表还有很多可以深挖的细节,此处可以放到研究STL的时候,详细了解。
常用的哈希结构——
注:表格参考代码随想录
-
数组
用数组表示,value就是index,数组类型可以有所不同
-
set(集合
集合又分为以下三种
集合 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率 std::set 红黑树 有序 否 否 O(logn) O(logn) std::multiset 红黑树 有序 是 否 O(logn) O(logn) std::unordered_set 哈希表 无序 否 否 O(1) O(1) -
map(映射
map也可以分为以下三种
映射 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率 std::map 红黑树 有序 否 否 O(logn) O(logn) std::multimap 红黑树 有序 是 否 O(logn) O(logn) std::unordered_map 哈希表 无序 否 否 O(1) O(1)
242 有效的字母异位词 easy
有两个字符串,判断组成这两个字符串的字母和数量是不是都一样
方法是,先建立一个unordered_map
,遍历其中一个字符串,记录各字符出现的次数
然后再遍历第二个字符串,清除各字符出现的次数,再遍历第三次,如果某字符串出现的次数小于0,就返回false
由于是字母,所以用hash数组表示也可以
bool isAnagram(string s, string t) {
int hash [26] = {};
for (char c: s) {
hash[c - 'a']++;
}
for (char c: t) {
hash[c - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (hash[i] != 0)
return false;
}
return true;
}
349 两个数组的交集 easy
先把一个数组遍历一遍,把出现过的数字放在unordered_set
中,
然后再遍历第二个数组,找数字是不是在哈表集合中出现,如果出现了,就记录一下结果,记录结果也要使用一个set,因为放置重复的元素出现
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> res;
unordered_set<int> intersection(nums1.begin(), nums1.end());
for (int num: nums2) {
if (intersection.find(num) != intersection.end())
res.insert(num);
}
return vector<int>(res.begin(), res.end());
}
350 两个数组的交集II easy
与上一题不同,这次要统计的结果中每个元素出现的次数,应当与该元素在两个数组中都出现的次数一致,出现次数不一致,那么就返回较小值
方法就是用一个哈希map,记录每个数字出现的次数,遍历第二个数组的时候,减去数字出现的次数,如果这个数出现的次数等于0,那么在map中删除该数字就可以了
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) {
return intersect(nums2, nums1);
}
unordered_map <int, int> m;
for (int num : nums1) {
++m[num];
}
vector<int> intersection;
for (int num : nums2) {
if (m.count(num)) {
intersection.push_back(num);
--m[num];
if (m[num] == 0) {
m.erase(num);
}
}
}
return intersection;
}