文章目录
【一】 Hash Table(哈希表)& Hash Function(哈希函数)& Collisions(哈希碰撞 / 冲突)
- Hash Table + Hash Function
![](https://i-blog.csdnimg.cn/blog_migrate/ff1534a110cb84bb5941b2641b25092e.png)
- Hash Collisions - 拉链法(在 同一位置 引出 链表 进行存储)
![](https://i-blog.csdnimg.cn/blog_migrate/d3c12228a5fe24030131d244ca57a498.png)
【二】 List(列表)vs Map(图)vs Set(集合)- 解释性的数据结构
- List:list_x = [1, 2, 3, 4]
- Map:map_x = { ‘jack’ : 100, ‘joyce’ : 90, ‘Eric’ : 80 }
- Set:set_x = { ‘jack’, ‘joyce’, ‘Eric’ }
set_y = set ( [ ‘jack’, ‘joyce’, ‘Eric’ ] )
【三】 Hash Map(哈希图)vs Tree Map(树图)+ Hash Set(哈希集合)vs Tree Set(树集合)
- Hash Map best practices(不同语言的使用)
![](https://i-blog.csdnimg.cn/blog_migrate/27ab082e766ee005c274ef1a512f41d4.png)
- Hash Set best practices(不同语言的使用)
![](https://i-blog.csdnimg.cn/blog_migrate/4b8a3469424a21bf7b5a131529c940ca.png)
- Time Complexity(时间复杂度) Hash 略优于 Binary Search Tree,但 Tree 结构相对有序
![](https://i-blog.csdnimg.cn/blog_migrate/9727a2b06534890c406ed0e938a417d2.png)
【四】 Interview(面试题)
【4.1】 LeetCode 242:Valid Anagram(有效的字母异位词)
题目说明:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词
示例1:s = “anagram”, t = “nagaram”, true
示例2:s = “rat”, t = “car”, false
- sort(排序):O (NlogN)
# python 1
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
return sorted(s) == sorted(t)
- Map 计数:O (N)
// c++(用数组代替哈希表)
class Solution {
public:
bool isAnagram(string s, string t) {
if(s.size() != t.size()) return false; // 先判断两个字符串的长度是否相等
int m[26] = {0}; // 用数组代替哈希表
for(int i = 0; i < s.size(); i++) {
++m[s[i] - 'a']; // 用ASCALL码值计算位置
}
for(int i = 0; i < t.size(); i++) {
if(--m[t[i] - 'a'] < 0) return false; // 先自减再判断
}
return true;
}
};
# python 2
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
dic1, dic2 = {}, {} # 用哈希表实现
# dict.get(key, default=None)
# key -- 字典中要查找的键
# default -- 如果指定键的值不存在时,返回该默认值
for item in s:
dic1[item] = dic1.get(item, 0) + 1
for item in t:
dic2[item] = dic2.get(item, 0) + 1
return dic1 == dic2
# python 3
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
dic1, dic2 = [0]*26, [0]*26 # 自定义哈希表,26个字母
for item in s:
dic1[ord(item) - ord('a')] += 1 # 用ASCALL码计算位置
for item in t:
dic2[ord(item) - ord('a')] += 1 # 用ASCALL码计算位置
return dic1 == dic2
【4.2】 LeetCode 1:Two Sum(两数之和)
题目说明: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标
示例:nums = [ 2, 7, 11, 15 ], target = 9, 返回 [ 0, 1 ]
- Map :O (N)
// c++( unordered_map 哈希表 )
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> m;
vector<int> res;
for(int i = 0; i < nums.size(); i++) {
m[nums[i]] = i;
}
for(int i = 0; i < nums.size(); i++) {
int t = target - nums[i];
if(m.count(t) && m[t] != i) {
res.push_back(i);
res.push_back(m[t]);
break;
}
}
return res;
}
};
# python
# 挖个坑,这里还没解决用 dict() 结构实现哈希的方法,继续琢磨
# 当测试用例为 [3, 3], 6 的情况下,dict() 会重置同一个键('3')的值
# 已解决
【4.3】 LeetCode 15:Three Sum(三数之和)
题目说明: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组
示例:nums = [-1, 0, 1, 2, -1, -4],满足要求的三元组集合为:[ [-1, 0, 1], [-1, -1, 2] ]
- Map :O (N^2)
# python 1( 两层 for 循环,map 存储 -v-x )
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
nums.sort()
res = set() # 利用 set 的元素不重复性
for i, v in enumerate(nums[:-2]):
if i >= 1 and v == nums[i-1]:
continue
dic = {}
for x in nums[i+1:]:
if x not in dic:
dic[-v-x] = 1 # 添加进哈希图
else:
res.add((v, -v-x, x))
return list(res)
- 排序 + 双向遍历(【-4】, -1, -1, 0 , 1, 2)- 剩余的数组从两端向中间逼近
// c++( 要熟悉 vector 的操作 )
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res; // vector 容器
sort(nums.begin(), nums.end()); // 排序
if (nums.empty() || nums.back() < 0 || nums.front() > 0) return {}; // 先判断排序后的数组
for (int k = 0; k < nums.size(); ++k) {
if (nums[k] > 0) break;
if (k > 0 && nums[k] == nums[k - 1]) continue; // 跳过重复 fix 的数字
int target = 0 - nums[k];
int i = k + 1, j = nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.push_back({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + 1]) ++i; // 跳过 相同 的数字
while (i < j && nums[j] == nums[j - 1]) --j; // 跳过 相同 的数字
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return res;
}
};
# python 2( 思路跟 c++ 一样 )
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
nums.sort()
for i in range(len(nums)-2):
if i > 0 and nums[i] == nums[i-1]:
continue # 判断当前数是否与前一个数相同,相同则跳过
l, r = i+1, len(nums)-1
while l < r:
s = nums[i] + nums[l] + nums[r]
# 判断 s 大于或小于或等于 0 的情况
if s < 0:
l = l + 1
elif s > 0:
r = r - 1
else:
res.append((nums[i], nums[l], nums[r]))
# 判断邻近的值是否相等,相等则跳过
while l < r and nums[l] == nums[l+1]:
l = l + 1
while l < r and nums[r] == nums[r-1]:
r = r - 1
l = l + 1
r = r - 1
return res
【4.4】 Python:实现哈希表
key 值可以通过 ASCII 码映射成 int 的类型
# 实现了哈希表的插入和读取操作,key 只考虑了 int 类型的情况
classs MyHash(object):
def __init__(self, length=10):
self.length = length
self.items = [[] for i in range(self.length)]
# 哈希函数
def hash(self, key):
# 拉链法,计算 key 对应的在哪个链中
return key % self.length
def equals(self, key1, key2):
# 判断两个 key 是否相同
return key1 == key2
# 添加操作
def insert(self, key, value):
# 通过 key 值找到对应的那个 list
index = self.hash(key)
# 在那个 list 下再去遍历里面的值
if self.items[index]:
for item in self.items[index]:
# 如果 key 值已经存在
if self.equals(key, item[0]):
self.items[index].remove(item)
break
self.items[index].append((key, value))
return True
# 读取操作
def get(self, key):
index = self.hash(key)
if self.items[index]:
for item in self.items[index]:
# 如果找到了key值相同的,就返回对应的 value
if self.equals(key, item[0]):
return item[1]
# 如果 key 值对应的 list 为空,则抛出异常
raise KeyError
# 插入
def __setitem__(self, key, value):
# 支持用户插入数据,如 myhash[1] = 1
return self.insert(key, value)
# 读取
def __getitem__(self, key):
# 支持用户读取, 如 myhash[1]
return self.get(key)