leetcode-哈希表
一般哈希表都是用来快速判断一个元素是否出现集合里。
使用数组和set来做哈希法的局限:
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key。
- map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下标。
1、有效的字母异位词(easy排序或哈希)
242 有效的字母异位词
因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下表0,相应的字符z映射为下表25。
再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。
那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。
那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。
最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s) != len(t):
return False
records = [0]*26
##并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
for i in s:
records[ord(i) - ord('a')] += 1
for i in t:
records[ord(i) - ord('a')] -= 1
return records == [0]*26
2、两个数组的交集(easy)
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
s1 = set(nums1)
s2 = set(nums2)
res = list()
for i in s1:
if i in s2:
res.append(i)
return res
3、快乐数(not done)
202 快乐数
题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
class Solution:
def isHappy(self, n: int) -> bool:
def calculate_happy(num):
sum_ = 0
# 从个位开始依次取,平方求和
while num:
sum_ += (num % 10) ** 2
num = num // 10
return sum_
# 记录中间结果
record = set()
while True:
n = calculate_happy(n)
if n == 1:
return True
# 如果中间结果重复出现,说明陷入死循环了,该数不是快乐数
if n in record:
return False
else:
record.add(n)
4、两数之和(easy)
class Solution:
#哈希法
def twoSum(self, nums: List[int], target: int) -> List[int]:
records = dict()
# 用枚举更方便,就不需要通过索引再去取当前位置的值
for idx, val in enumerate(nums):
if target - val not in records:
records[val] = idx
else:
return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引
5、四数相加ii(done)
454 四数相加II
我们可以将四个数组分成两部分,A 和 B 为一组,C 和 D 为另外一组。
对于 A 和 B,我们使用二重循环对它们进行遍历,得到所有 A[i]+B[j]的值并存入哈希映射中。对于哈希映射中的每个键值对,每个键表示一种 A[i]+B[j],对应的值为 A[i]+B[j]出现的次数。
对于 C 和 D,我们同样使用二重循环对它们进行遍历。当遍历到 C[k]+D[l]时,如果 -(C[k]+D[l]) 出现在哈希映射中,那么将 -(C[k]+D[l])对应的值累加进答案中。
最终即可得到满足 A[i]+B[j]+C[k]+D[l]=0的四元组数目。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
if n1 + n2 in hashmap:
hashmap[n1+n2] += 1
else:
hashmap[n1+n2] = 1
# if the -(a+b) exists in nums3 and nums4, we shall add the count
count = 0
for n3 in nums3:
for n4 in nums4:
key = - n3 - n4
if key in hashmap:
count += hashmap[key]
return count
6、赎金信(easy)
383 赎金信
统计字符串ransomNote, magazine字符出现的次数,ransomNote的每个字符在magazine中,且个数小于等于magazine中该字符的个数,则return True
def canConstruct(ransomNote, magazine):
arr = [0] * 26
#通过arr记录 magazine里各个字符出现次数
for i in magazine:
arr[ord(i) -ord('a')] += 1
for i in ransomNote:
#如果等于零说明ransomNote里出现的字符,magazine没有
if arr[ord(i) - ord('a')] == 0:
return False
#遍历ransomNote,在arr里对应的字符个数做-操作
else:
arr[ord(i) - ord('a')] -= 1
return True
7、三数之和(done)
15 三数之和
首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i] b = nums[left] c = nums[right]。
接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
ans = []
n = len(nums)
nums.sort()
for i in range(n):
left = i + 1
right = n - 1
if nums[i] > 0: #第一个数就大于0了,不存在和为0
break
if i >= 1 and nums[i] == nums[i - 1]: #去重处理,仅对第一个数i
continue
while left < right:
total = nums[i] + nums[left] + nums[right]
if total > 0:
right -= 1
elif total < 0:
left += 1
else:
ans.append([nums[i], nums[left], nums[right]])
while left != right and nums[left] == nums[left + 1]: left += 1 #对第二个数做去重
while left != right and nums[right] == nums[right - 1]: right -= 1 #对第三个数做去重复
left += 1
right -= 1
return ans
8、四数之和(done)
18 四数之和
不要判断nums[k] > target 就返回了,三数之和 可以通过 nums[i] > 0 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。
四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
n = len(nums)
nums.sort()
ans = []
for i in range(n): # 第一个数去重
if i > 0 and nums[i] == nums[i - 1]: continue
for j in range(i + 1, n): # 第二个数去重
if j > i + 1 and nums[j] == nums[j-1]: continue
left = j + 1
right = n - 1
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total > target:
right -= 1
elif total < target:
left += 1
else:
ans.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]: left += 1
while left < right and nums[right] == nums[right - 1]: right -= 1
left += 1
right -= 1
return ans