据说要熟悉下定义,检索下检索下~
哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素
那么哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。
例如要查询一个名字是否在这所学校里。
要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。
将学生姓名映射到哈希表上就涉及到了hash function ,也就是哈希函数。
哈希表的内部实现原理:哈希表的内部实现原理是利用哈希函数将键映射到存储桶(buckets)的索引上,从而实现高效的数据查找和插入操作。哈希函数将键转换为一个固定大小的哈希值,然后通过取模运算将哈希值映射到存储桶的索引上。
哈希函数是将输入(键)映射到固定大小的输出(哈希值)的函数。好的哈希函数应该具有以下特性:
- 一致性:对于相同的输入,始终产生相同的哈希值。
- 均匀性:尽可能均匀地将不同的输入映射到不同的哈希值,以减少哈希碰撞的概率。
- 高效性:计算速度快,适用于大规模数据。
哈希碰撞是指不同的键经过哈希函数计算后得到相同的哈希值,导致它们被映射到哈希表中的同一个存储桶。哈希碰撞是不可避免的,因为哈希函数的输出空间通常要远小于输入空间的大小。解决哈希碰撞的常见方法包括开放地址法、链地址法和再哈希法等。
常见的哈希表有数组、Set和Map。它们的区别如下:
- 数组:使用整数作为索引,将值存储在对应的数组位置上。数组可以看作是一种简单的哈希表,哈希函数即为索引计算函数。在数组中,键和值之间的映射是直接的,没有额外的数据结构。
- Set:Set是一种无重复元素的集合,它存储的是键的集合而不存储对应的值。Set使用哈希表来实现,通过哈希函数将键映射到存储桶中,以支持高效的查找和插入操作。
- Map:Map是一种键值对的映射结构,它存储的是键值对的集合。Map也使用哈希表来实现,通过哈希函数将键映射到存储桶中,并将值与键关联起来。
242.有效的字母异位词
1、数组方法~ 可以使用数组来实现简单的哈希表,其中数组的索引表示哈希值,数组元素存储对应的值。这种实现适用于哈希值的范围较小且连续的情况。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
# 数组方法:
record=[0]*26
for i in range(len(s)):
record[ord(s[i])-ord('a')]+=1
for j in range(len(t)):
record[ord(t[j])-ord('a')]-=1
for i in range(26):
if record[i]!=0:
return False
return True
2、敲敲,这题集合(Set)方法不合适,集合(Set)是由一组唯一旦无序的元素组成的数据结构。集合中的元素不能重复,且没有特定的顺序。集合通常用干判断元素的存在性和去重操作。
但这题不仅是元素存在,还有频次得问题,可以用字典~
PS. 字典(Dictionary)是由键-值对(Key-Value Pair)组成的数据结构。每个键(Key)都是唯一的,而值(Value)可以重复。字典通常用于存储和检索具有对应关系的数据。
代码中的char_freq
是一个字典(dictionary),用于保存字符串s
中每个字符出现的频率。字典的键(key)是字符,值(value)是该字符在字符串s
中出现的次数。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s) != len(t):
return False
char_freq={}
for char in s:
if char in char_freq:
char_freq[char]+=1
else:
char_freq[char]=1
for char in t:
if char in char_freq and char_freq[char]>0:
char_freq[char]-=1
else:
return False
return True
349. 两个数组的交集
给定两个数组 nums1
和 nums2
,返回 它们的交集。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
1、数组方法
# 错误记录: 这样写如果在nums1或nums2中由重复元素,无法正确识别,感觉还是集合合适。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
## 数组方法
res=[0]*10
result=[]
for i in range(len(nums1)):
res[nums1[i]]+=1
for i in range(len(nums2)):
res[nums2[i]]+=1
for i in range(10):
if res[i]>=2:
result.append(i)
return result
数组暂时没想到啥,记录次数好像复杂了,集合就可以判断在不在。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 集合方法
n1=set(nums1)
n2=set(nums2)
result=[]
for i in n1:
if i in n2:
result.append(i)
return result
第202题. 快乐数
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
想说,这种啊,新的定义就要想想,不过判断一个数 n
是不是快乐数读题其实有点哈希的意思的。
最开始339 / 420 个通过的测试用例,我服气的。n =1 好吧,我忘了,修改了
class Solution:
def isHappy(self, n: int) -> bool:
record=set()
while 1 not in record and n != 1:
n=self.squaresSum(n)
if n==1:
return True
if n in record:
return False
else:
record.add(n)
return True
# 定义一个函数去求每个位置的平方和吧
def squaresSum(self,n):
sum=0
while n:
sum+=(n%10)**2
n=n//10
return sum
1. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
找数组下标比较头疼,不过不难,嵌套下就好
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
my_set=set(nums)
#
for i in range(len(nums)):
if target-nums[i] in my_set:
j=i+1
while j<len(nums):
if nums[j]!=target-nums[i]:
j+=1
else:
return [i,j]
return []
完工,电脑死了两次,辛苦它了,最近霍霍的有点严重。