1 HashTable & Hash Function & Collisions
1.1 Hash Function
1.2 Hash Collisions
2 Map vs Set
List vs Map vs Set
list_x = [1,2,3,4];
map_x = {
'jack' : 100,
'张三' : 80,
'selina' : 90,
...
}
set_x = {'jack','selina','Andy'}
set_y = set{['jack','selina','jack']}
3 HashMap, HashSet, TreeMap, TreeSet
HashMap,HashSet 使用哈希表存储。O(1) 时间复杂度 乱序排列
Treemap,TreeSet 使用二叉树存储。O(log2) 时间复杂度 相对有序的排列
4 HashMap best practices
C++
std::unordered_map
std::map
std::inordered_set
std::set
哈希表略快于二叉搜索树,而二叉搜索树中的数据是相对有序排列的,对数据要求是有序的可使用二叉搜索树。
5 题目实战
5.1 有效的字母异位词
方法1: 使用排序
class Solution {
public:
bool isAnagram(string s, string t) {
sort(s.begin(),s.end());
sort(t.begin(),t.end());
if(s == t)
return true;
else
return false;
}
};
该方法的时间复杂度为O(NlogN)
方法2: 使用哈希表的思想
- 首先判断s和t的尺寸大小是否相等,如果不相等直接返回false
- 创建一个26个元素的数组v
- 如果s中存在++,如果t中存在–
- 最后检查数组v中是否存在非0的值,如果存在返回false。如果都不存在返回true
class Solution {
public:
bool isAnagram(string s, string t) {
if(s.size() != t.size())
return false;
vector<int> v(26,0);
for(int i = 0; i < s.size(); i++)
{
v[s[i] - 'a'] ++;
v[t[i] - 'a'] --;
}
for(int i = 0; i < 26; i++)
{
if(v[i] != 0) return false;
}
return true;
}
};
该方法的时间复杂度为O(N)
5.2 两数之和
考虑到两种方法,第一种是双指针法。
方法1 用双指针的方法
- left,right指针分别指向数组的头尾
- 判断left和right指向的数的和与target比较
- 如果sum(left_num + right_num) > target right –
- 如果sum(left_num + right_num) < target right ++
- 如果sum(left_num + right_num) == target right 返回 right 和 right 位置
方法2使用hash表方法。
首先考虑了两次hash的方法,就是先将数据存入hash表,再查找。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> hashtable;
for(int i = 0; i < nums.size(); i++){
hashtable[nums[i]] = i;
}
for(int j = 0; j < nums.size(); j++){
auto it = hashtable.find(target - nums[j]);
if(it != hashtable.end() && j != it->second){
return {j,it->second};
}
hashtable.erase(nums[j]);
}
return {};
}
};
看了例题的解答,可以只用一次hash解决
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end()) {
return {it->second, i};
}
hashtable[nums[i]] = i;
}
return {};
}
};
这里大概意思应该是,先查找后插入,因为是两个数字,当前一个数字插入后就能找到。