哈希表理论基础
哈希表是根据关键码的值而直接进行访问的数据结构。
代码随想录上给的例子:
那么哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。
例如要查询一个名字是否在这所学校里。
要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。
我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。
将学生姓名映射到哈希表上就涉及到了 hash function ,也就是哈希函数。
哈希函数
哈希函数,把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。
哈希函数如下图所示,通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。
哈希碰撞 Collisions
拉链法
冲突
线性探测法
保证tableSize>dataSize
常见的三种哈希结构
数组
set - O(log n)
map - O(log n)
| set | 红黑树 | 有序 | 不可有重复数值 | 不能更改数值 |
| multiset | 红黑树 | 有序 | 可以有重读数值 | 不可更改数值 |
| unordered_set | 哈希表 | 无序 | 不可有重复数值 | 不可更改数值 |
| map | 红黑树 | key有序 | key不可重复 | key不可修改 |
| multimap | 红黑树 | key有序 | key可重复 | key不可修改 |
| unordered_map | 哈希表 | key无序 | key不可重复 | key不可修改 |
242.有效的字母异位词 Valid Anagram
先遍历s字符串中的字符进行查数并放在查数的数组里(有几个字符那么对应的查数数组+1)
再遍历t字符串中的字符进行查数,并减去已有的.
最后对比查数数组,如果为0则true,不为0则是false.
class Solution {
public:
bool isAnagram(string s, string t) {
int order[26] = {0};
for (int i = 0; i < s.size(); i++){
order[s[i]-'a']++;
}
for (int i = 0; i < t.size(); i++){
order[t[i]-'a']--;
}
for (int i = 0; i < 26; i++){
if (order[i] != 0){
return false;
}
}
return true;
}
};
349. 两个数组的交集 Intersection of Two Array
nums<=1000 用数组比set做这道题更好
这题用unorder_set做,输出结果需要去重.
直接插入到set中: unordered_set<int> nums_set(nums1.begin(),nums1.end());
查找的话需要不等于set的尾: if (nums_set.find(num) != nums_set.end())
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set;
unordered_set<int> nums_set(nums1.begin(),nums1.end());
for (int num : nums2){
if (nums_set.find(num) != nums_set.end()){
result_set.insert(num);
}
}
return vector<int>(result_set.begin(),result_set.end());
}
};
202.快乐数 Happy Number
要么结果为1,要么是一个一直循环的数.
当在hashset里查找会不会有循环里出现过的数字. if (set.find(temp) != set.end())
如果赶回一个set里有过的数字会直接返回false,因为set里数字不能重复.
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> set;
while (n != 1){
int temp = 0;
while (n != 0){
int digit = n % 10;
temp += digit * digit;
n /= 10;
}
if (set.find(temp) != set.end()){
return false;
} else {
set.insert(temp);
}
n = temp;
}
return true;
}
};
1. 两数之和
用map是最好的解法, 可以直接保存下标.
首先拿target减去现在的数,进行查找,找到了直接输出下标.
map.insert(pair<int,int>(nums[i],i)) 也可以写成 map[nums[i]] = i
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for (int i = 0; i < nums.size(); i++){
auto iter = map.find(target - nums[i]);
if (iter != map.end()){
return {iter->second, i};
}
map.insert(pair<int,int>(nums[i],i));
}
return {};
}
};