一、认识哈希表
- 数组本质上就是一张哈希表(也称为散列表),哈希表只不过把数组的索引显式表示出来了。所以数组和哈希表查询的时间复杂度都是O(1),一般会用来快速判断一个元素是否在集合中。其添加和删除的时间复杂度是O(n),因为删除或者添加一个元素后面的元素要补上去。
- 与之相对应的是链表,删除和添加的时间复杂度是O(1),查询是O(n),因为最坏的情况是要一直查找到最后一个元素。
二、哈希表的作用
- 统计字符串中所有元素的个数
- 根据唯一索引(分类标志),来存储对应的属于同一组的元素
三、哈希法
- 适用哈希法,一般会选择以下数据结构:set(集合)、字典、数组:【异位词】
- 哈希法查找实际是牺牲时间换取空间,因为需要额外的数组、set或者字典来存储数据,才能实现快速的查找。【异位词组】
四、例题
(一)找重合
- 实质:判断双序列元素及元素个数是否一致
调包
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
from collections import Counter
return Counter(s)==Counter(t)
一个哈希表
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
# 先对s的所有字母构建字典,再根据t的构成对这个字典判断个数是否正确
hash=dict()
for i in s:
if i in hash:hash[i]+=1 # 如果在就累加1,如果不在就返回0
else:hash[i]=1
for j in t:
if j in hash:hash[j]-=1 # 在就-1,不在就返回1
else:return False
# 判断最后字典的value中是否有非零元素
for value in hash.values():
if value!= 0:return False
return True
两个哈希表判断是否相等
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
from collections import defaultdict
s_dict = defaultdict(int) # 如果key不存在时,则默认返回0
t_dict = defaultdict(int)
for x in s:
s_dict[x] += 1
for x in t:
t_dict[x] += 1
return s_dict == t_dict
判断两个单词是否互为异位词>>判断一群单词中的异位词对,并用列表的形式存储起来
【法一】defaultdict(list)
- 思路:可以用defaultdict(list)的结构来存储满足相同条件的元素都存储在同一列表中的要求,最后返回list(res.values())来呈现出列表中的列表形式
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
# 可以用defaultdict(list)的结构来存储列表中的列表格式
res=collections.defaultdict(list)
# 将所有单词排序,并以排序后的单词为key,来存储单词
for str in strs:
key=''.join(sorted(str))
res[key].append(str) # 字典中value为列表
return list(res.values())
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
set1,set2=set(nums1),set(nums2)
return list(set1&set2)
350. 两个数组的交集 II
【法一】交集,之后统计元素个数
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
set1,set2=set(nums1),set(nums2)
intersection=list(set1&set2) # 先得到元素
res=[]
for i in intersection: # 再扩充元素的个数
n=min(nums1.count(i),nums2.count(i))
res=res+([i]*n)
return res
【法二】先对一个列表计数,然后遍历另一个,更正交集元素的个数,同时也录入交集元素。
- 代码技巧:为了节省时间,先对短的列表进行计数,因为计数对每个字符都要遍历n次。然后在统计交集元素个数的时候,对另一个列表的每个元素遍历,取最小(用减一法)
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
if len(nums1)>len(nums2):
nums1,nums2=nums2,nums1
from collections import Counter
counter_1=Counter(nums1) # 假设nums1是短列表
res=[]
# 判断一个字典中的元素是否在另一个中,并找到最小的个数
for key in nums2:
if key in counter_1 and counter_1[key]>0:
res.append(key)
counter_1[key]-=1 # key是数字,value是个数
else:continue
return res