哈希表理论基础
哈希表用于快速判断一个元素是否出现在集合中,查询复杂度为O(1)
原数据经过hashFunction得到index,再对哈希表size取模,以免超出
哈希碰撞的解决方法:拉链法,线性探测法
三种常用的数据结构:数组,set,map
242.有效的字母异位词
题目:
给定两个字符串 s
和 t
,编写一个函数来判断 t
是否是 s
的字母异位词。
注意:若 s
和 t
中每个字符出现的次数都相同,则称 s
和 t
互为字母异位词
思路:如果字符串的长度不等,肯定不是字母异位词。初始化一个字典,使其所有的key值都为0,统计字符串中的字符数量,有就加,然后继续遍历下一个字符串,有就减,最后遍历差值,如果字符数量一致则为字母异位词(重排)。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s)!=len(t):
return False
#初始化字典dic,且所有key的初始value都为0
dic=defaultdict(int)
#统计字符串s各字符的数量,遇到就+1
for c in s:
dic[c]+=1
for c in t:
dic[c]-=1
#遍历差值,若字符数量不一致,则不互为重排
for val in dic.values():
if val!=0:
return False
return True
时间复杂度:O(m+n) 两条字符串三轮循环迭代
题目:给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
思路:初始化两个计算长度的数组,提示给出题中两个数组的在0到一千,所以初始化长度为1001,创建一个空列表用于储存数据,遍历两个数组并把两个数组中的元素暂时储存到开始两个计算长度的数组中,设定一个变量k,若两个数组中都有k则把k添加到空列表中。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
count1=[0]*1001
count2=[0]*1001
res=[]
for i in range(len(nums1)):
count1[nums1[i]]+=1
for j in range(len(nums2)):
count2[nums2[j]]+=1
for k in range(1001):
#如果里面有一个没有k则为0,只有同时有k才>0
if count1[k]*count2[k]>0:
res.append(k)
return res
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
#具体来说,table.get(num, 0) 这个语句会尝试从 table 中获取键为 num 的值,如果 num 存在于 table 中,则返回对应的值,否则返回默认值 0。然后将这个值加1,表示 num 在 nums1 中出现的次数,最后将结果存储在 table 中。
res=set()
for num in nums2:
if num in table:
res.add(num)
del table[num]
return list(res)
题目:
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
思路: 使用set集合,把n添加到集合中,这里record时一个集合,用来储存每一次计算得到的新数字n,当出现重复数字时,说明进入了循环。把n当成字符串进行拆分,得到每个位数的平方和,判断值是否为1,若没有则将得到的新数字赋值给n,来使下一个循环继续对新数字进行计算。
class Solution:
def isHappy(self, n: int) -> bool:
record=set()
while n not in record:
record.add(n)
new_num=0
n_str=str(n)
for i in n_str:
new_num+=int(i)**2
if new_num==1:
return True
else:n=new_num
return False
时间复杂度:O(logn)
题目:
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
思路:可以采取暴力枚举解法,遍历n 判断与目标值是否相等再返回。
class Solution:
def twoSum(self, nums, target):
n=len(nums)
for i in range(n):
for j in range(i+1,n):
if nums[i]+nums[j]==target:
return[i,j]
创建一个哈希表来判断值。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dict={}
n=len(nums)
for i in range(n):
if target-nums[i] not in dict:
dict[nums[i]]=i
else:
return [dict[target-nums[i]],i]
还有一些Python方法
1.defaultdict() 创建一个特殊的字典,key不存在则返回一个默认值,参数为list,str,int等
2.Counter() 函数,统计可迭代对象中各元素重复的次数,需要from collections import Counter,返回一个Counter对象,可以直接dict构建字典,也可以for k,v in Counter 来遍历访问
3.ord() 用于取字符的ASCII码
4.set创建的集合可以用&取交集,用|取并集,用-取差集运算
5.divmod(a,b) 函数返回结果是a/b的商和余数,只需要b取10,再把商赋值给原数字,即可不断从小到大取得单位数字,也即 n, v = divmod(n, 10), v即为从小到大取出来的单位数字
6.str(int) 可以直接把数字转换为字符串,如123转为’123’,如此便可以直接以列表形式访问单位数字
7.list.sort() 直接对原list排序,返回值为空,类似的还有remove()函数,要注意这类无返回值的函数
8.sorted(list)会返回一个新创建的列表
9.深浅拷贝问题!!a = [1,2,3],若赋值b=a,则a,b指向的是同一个列表!改变b会把a改变,这是浅拷贝,如果b = [i for i in a],则可以深拷贝一层,也即列表的第一维深拷贝了,但是二维列表的大于等于第二维仍然浅拷贝,因为实际存的是一个列表地址(b = a.copy()也一样的)。真正深拷贝只有import copy的copy.deepcopy()函数