代码随想录第六天哈希表part01|242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1.两数之和
哈希表理论基础
哈希表(英文名为Hash table),是根据关键码的值而直接进行访问的数据结构,直白来讲其实数组就是一张哈希表。哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。
哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。
例如要查询一个名字是否在这所学校里。要枚举的话时间复杂度是O(n),但如果使用哈希表的话,只需要O(1)就可以做到。我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。
哈希函数
哈希碰撞
列表中多个值索引到了哈希表中一个位置
两种解决方法:拉链法和线性探测法
常见的三种哈希结构
list(数组)、set(集合)、map(映射)
对于集合,分三种:set,multi set、unordered set
①集合(Set)是一种包含已排序对象的关联容器。 set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的数据结构,在插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,它不会插入相同键值的元素,而采取忽略处理。
②multiset基本和set一样,但是这个允许插入重复的键值!因为包含重复元素,所以,在插入元素、删除元素、查找元素上较set有差别
③unordered_set是无序的,与set相比运行较快,内存占用较大。基本操作与set相同。
242.有效的字母异位词
思路
:
判断两个字符串是否由相同的字符组成
①暴力法:两个for循环,分别遍历两个字符串
②哈希法:a-z的ASCII码是连续的,可以映射到0-26上
hash = []定义一个数组,先统计第一个字符串每一个字母出现的频率,在第二个字符串中做相应的减法
伪代码
:
for(i=0; i<s.size; i++)
hash[s[i]-'a']++
for(i=0; i<t.size; i++)
hash[s[i]-'a']--
for(i=0; i<26; i++)
if(hash[i]) != 0) return false
return true
python代码
:
python中用ord(‘a’)获得字符a的ASCII码
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
hash = [0]*26
for i in s:
hash[ord(i) - ord('a')] += 1
for i in t:
hash[ord(i) - ord('a')] -= 1
for i in range(26):
if hash[i] != 0:
return False
return True
349. 两个数组的交集
该题相比上题,没有数值的限制,nums1可能会非常大,不适用于数组处理
哈希表擅长:给你一个元素,判断在集合里是否出现过,再具体分析用数组、set还是map:如果数值很大不适合用数组,而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。不要小瞧这个耗时,在数据量大的情况,差距是很明显的。
本题中特意说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的,同时可以不考虑输出结果的顺序
思路
:
先遍历nums1,将数放入set中,再遍历nums2,如果该数在set里面存在,就将其存入result列表中。
set、multi set、unordered set 红黑树、数组【这里不太懂,python中没有unordered_set这个数据结构】
这里用underordered set
伪代码
:
unordered_set result
unordered_set num_set(nums1) // 把nums1数组转换为unordered_set数据类型
for(i=0; i<num2.size; i++) // nums2进行查询操作
if(num_set.find(nums2[i]) != num_set // 如果找到了这个元素
result.insert(nums2[i])
return vector(set) // 要返回的是数组,不是集合
// 用数组做
int hash[1005] = {0}
unordered_set result
for(i=0; i<num2.size; i++)
hash[nums[i]] = 1
for(i=0; i<nums2.size; i++)
if(hash[nums2[i]] == 1)
result.insert(nums2[i])
return vector(set)
python代码
:
补充:python中字典的get()方法
dict.get(key[, value])
key – 字典中要查找的键。
value – 可选,如果指定键的值不存在时,返回该默认值。
get() 方法 Vs dict[key] 访问元素
get(key) 方法在 key(键)不在字典中时,可以返回默认值 None 或者设置的默认值;dict[key] 在 key(键)不在字典中时,会触发 KeyError 异常。
// 使用字典+集合
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 用字典(哈希表)存储一个数组中的所有元素
table = {}
for num in nums1:
table[num] = table.get(num, 0) +1
# 使用集合存储最终结果
res = set()
for num in nums2:
if num in table:
res.add(num)
del table[num]
return list(res)
// 使用数组
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
hash = [0]*1005
result = set()
for i in nums1:
hash[i] = 1
for j in nums2:
if(hash[j] == 1):
result.add(j)
return list(result)
202. 快乐数
思路
解题关键:题目中:也可能是 无限循环 但始终变不到 1,无限循环,也就是说求和的过程中,sum会重复出现。
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
判断sum是否重复出现就可以使用unordered_set。
python代码
python中divmod函数介绍:divmod()函数把除数和余数运算结果结合起来
例如,divmod(a, b),返回一个包含商和余数的元组(a // b, a % b)
class Solution:
def isHappy(self, n: int) -> bool:
sumset = set()
newsum = n
while newsum != 1:
newsum = self.get_sum(newsum)
if newsum in sumset:
return False
else:
sumset.add(sum)
return True
def get_sum(selg, n):
newsum = 0
while n:
n, r = divmod(n, 10)
newsum += r**2
return newsum
1.两数之和
思路
运用哈希表的经典算法,本题使用map解决。
什么时候用哈希表做映射:判断这个元素是否出现过,遍历到元素n,判断target-n是否遍历过,该元素是否在集合里出现过,同时我们还要知道这个元素在数组里的下标
那我们用什么数据结构来作为这个集合呢?既要获取这个元素的值,又要获取这个元素的下标,用数组和set都不行了,用map,key(元素):value(下标)。
map存放我们遍历过的元素
C++中有3种map:map unorderedmap mutimap
Python中使用字典?
伪代码 (C++)
unordered_map(int, int) map
for(i=0; i<nums.size; i++)
s = target - nums[i]
iter = map.find(s)
if (iter != map.) // 如果元素在map中出现
return {iter->value, i}
else
map.insert(nums[i], i)
python代码
注意while中的边界条件需要仔细考虑,while curr而不是while curr.next,因为最后一个是空指针,temp = curr.next
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
mapdict = {}
for i in range(len(nums)):
if target - nums[i] in mapdict:
return [i, mapdict[target - nums[i]]]
else:
mapdict[nums[i]] = i
return []
时间复杂度:O(n)
空间复杂度:O(n)