今天用一篇博客把所有的哈希表内容总结起来~~
首先,什么时候想到用哈希表呢:当需要判断一个元素是否在一个集合中时。哈希表有三种,数组,set和map,要分情况看如何使用。
242.有效的字母异位词
这道题很有意思,属于是不学哈希表根本想不到该怎么做的那种。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
record = [0] * 26
for i in s:
record[ord(i) - ord('a')] += 1
for i in t:
record[ord(i) - ord('a')] -= 1
for i in record:
if i != 0:
return False
return True
方法是创建一个数组record来作为“哈希表”。因为我们需要存储的部分,也就是字母,的个数是确定的,只有26位。那我们怎么定位到每个字母的索引呢?需要用ord(i)来找到ASCII码。最后通过判断record中是否每个字母对应的出现次数都是0即可。
349. 两个数组的交集
第一种方法,使用set作为哈希表来进行储存。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
table = {}
for i in nums1:
table[i] = table.get(i,0) + 1
count = set()
for i in nums2:
if i in table:
count.add(i)
del table[i]
return list(count)
在这种方法里,需要注意的点有以下几个:(1)table.get(i,o)这个用法很棒,指的是如果table里有一个key名为i,就取出那个key所对应的value,不然就输出0;(2)每次在count里加入了i,就要把它从table里删去,以此避免重复出现。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2))
这个方法我最爱了,直接用set的函数,不带一点拖泥带水的。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
a = [0] * 1000
b = [0] * 1000
for i in nums1:
a[i] += 1
for i in nums2:
b[i] += 1
results = []
for i in range(1000):
if a[i] * b[i] > 0:
results.append(i)
return results
第三种方法是根据leetcode的新要求,nums1和nums2中的数字都不超过1000这个条件确定的。因为都不超过1000,所以可以创立两个数组a和b,在对应数字出现的时候将计数+1,这样同样的数字都出现的时候才会把它加入到最终的results中。
202.快乐数
这道题的关键是,要判断是否无限循环,无限循环就是和出现过的意思。因此要增加一个判断。同时还需要知道使用divmod函数,用来计算n各个位数上数字的平方和。总体来说代码如下:
class Solution:
def isHappy(self, n: int) -> bool:
record = set()
while True:
n = self.sum_n(n)
if n == 1:
return True
if n in record:
return False
else:
record.add(n)
def sum_n(self, n:int) -> int:
sum_all = 0
while n:
n, r = divmod(n,10)
sum_all += r**2
return sum_all
1. 两数之和
这道题在博客里也说得很清楚啦,主要就是几个点:
1)如何想到使用哈希表;2)哈希表为什么要使用map;3)如何实现哈希表;4)key和value分别存储什么。
最终的实现也很方便,可以用字典实现(key,value)对的存储,也可以用set,index就是索引,出现的位置,然后存储value。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
record = {}
for index, value in enumerate(nums):
temp = target - value
if temp in record:
return [record[temp], index]
else:
record[value] = index
return []
6. 四数相加
这道题的思路很好,很多时候我们都避免用两个for循环,但是这道题偏偏就用了两个for,只要能解决问题就是好思路!
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
colle = {}
for n1 in nums1:
for n2 in nums2:
if (n1+n2) in colle:
colle[n1+n2] += 1
else:
colle[n1+n2] = 1
count = 0
for n3 in nums3:
for n4 in nums4:
if (-n3-n4) in colle:
count += colle[-n3-n4]
return count
383. 赎金信
这道题不难,但是有非常多种有意思的解法。比如说collections函数中的defaltdict, counter,以及count用法等等。这次来不及啦,二刷的时候补上~~
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
dic = {}
for i in magazine:
dic[i] = dic.get(i, 0) + 1
for i in ransomNote:
if i in dic and dic[i] > 0:
dic[i] -= 1
else:
return False
return True
15. 三数之和
这道题最重要的思路,也是最麻烦处理的地方,是不可包含重复的三元组。为了解决这个问题,需要在多个地方予以限制。也正是因为这个问题的存在,不能使用哈希,而用快慢指针来完成。
需要注意的,首先是i和左边的不相同,然后是left和右边、right和左边不相同。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
result_all = []
nums.sort()
for i in range(len(nums)):
if nums[i] > 0:
return result_all
if i > 0 and nums[i] == nums[i-1]:
continue
left, right = i+1, len(nums)-1
while left < right:
result = nums[left] + nums[right] + nums[i]
if result > 0:
right -= 1
elif result < 0:
left += 1
else:
result_all.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 result_all
18. 四数之和
好耶!!这道题是自己写出来的,开心呜呜呜呜。剪枝操作本身可有可无,在大规模方面的优化领域是有意义的,在力扣里可以省去。需要注意一些细节思路都很清晰。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
result = []
for i in range(len(nums)):
#以下两行为剪枝操作,可以省略
if nums[i] > target and nums[i] > 0 and target >0:
return result
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, len(nums)):
#以下两行为剪枝操作,可以省略
if (nums[j] > target - nums[i]) and (target > 0):
break
if j > i+1 and nums[j] == nums[j-1]:
continue
left, right = j+1, len(nums) - 1
while left < right:
s = nums[i] + nums[j] + nums[left]+ nums[right]
if s < target:
left += 1
elif s > target:
right -= 1
else:
result.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 result
总结一下!哈希表有三种:数组、set和map。
数组是在出现元素固定的时候比较常用,set则更倾向于不重复元素,而对于map来说则是需要key和value共同出现的时候使用比较合适。
二刷的时候要理解得更深入一些!!!