算法记录 | Day6哈希表基础Ⅱ
LeetCode 454-四数相加Ⅱ
题目描述:给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
解题思路
- 没什么思路的题,只知道暴力解法,所以看了题解之后才知道的
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
# a + b + c + d = 0
# (a+b) + (c+d) = 0
n = len(nums1)
# a+b 的结果
hash_ab = dict()
for i in range(n):
for j in range(n):
res = nums1[i] + nums2[j]
if res not in hash_ab:
hash_ab[res] = 1
else:
hash_ab[res] += 1
print(hash_ab)
# c+d 的结果
# 这里统计count,知道元组有多少个
count = 0
for n3 in nums3:
for n4 in nums4:
key = - n3 - n4
if key in hash_ab:
count += hash_ab[key]
return count
注意:
记录次数之后,找key值的时候要加次数。自己写第一遍的时候发现了不记录次数的话,每次只能count+1,会漏掉值相等的一种情况。
难点
- 如何思考题解是将ab相加,找bc的过程,看数学敏感度么。。
总结
hash表可用来记录次数
LeetCode 383-救赎金
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
输入:ransomNote = "a", magazine = "b"
输出:false
解题思路
- 我的写法
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
# 这题究竟是包含字母一样就行,还是顺序也要一样?aa 和 aba正确么?
# 先按照包含字母一样即可做
hashmap = dict()
for i in magazine:
if i not in hashmap:
hashmap[i] = 1
else:
hashmap[i] += 1
for i in ransomNote:
if i not in hashmap:
return False
if i in hashmap:
hashmap[i] -= 1
for j in hashmap:
if hashmap[j] < 0:
return False
return True
注意:
- 理解题意
写法二:
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
arr = [0] * 26
for x in magazine:
arr[ord(x) - ord('a')] += 1
for x in ransomNote:
if arr[ord(x) - ord('a')] == 0:
return False
else:
arr[ord(x) - ord('a')] -= 1
return True
写法三:
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
c1 = collections.Counter(ransomNote)
c2 = collections.Counter(magazine)
x = c1 - c2
#x只保留值大于0的符号,当c1里面的符号个数小于c2时,不会被保留
#所以x只保留下了,magazine不能表达的
if(len(x)==0):
return True
else:
return False
注意:这个Counter的用法就比较神奇了。
- 哈希表在python中可以用collections.Counter计数来体现。该方法用于统计某序列中每个元素出现的次数,以键值对的方式存在字典中。但类型其实是Counter。
难点
- 多种写法,第二种和第三种写使用的时候都不太熟悉
总结
LeetCode 15-三数之和
题目描述:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
解题思路
- 双指针法
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# a + b + c = 0
n = len(nums)
res = []
# 先排序
nums.sort()
for a in range(n):
if nums[a] > 0:
return res
# 去重
if a>0 and nums[a] == nums[a-1]:
continue
left = a + 1
right = n - 1
while left < right:
total = nums[a] + nums[left] + nums[right]
if total > 0:
right -= 1
elif total < 0:
left += 1
else:
res.append([nums[a],nums[left],nums[right]])
# 去重 # 这里最开始写成了if,还是会出现重复错误
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 res
难点
- 双指针法
- 去重操作
总结
暂时可以先记住这种解法,三个数的和,三个数的集合如何写
LeetCode 18-四数之和
题目描述:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
解题思路
- 三数之和的基础上,继续加上一个for循环
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
# 三数之和的基础上再加for循环,去重
n = len(nums)
nums.sort()
res = []
for i in range(n):
# 去重的操作
if i > 0 and nums[i] == nums[i-1]:
continue
for k in range(i+1, n):
if k > i + 1 and nums[k] == nums[k-1]:
continue
## 双指针法
p = k + 1
q = n - 1
while p < q:
if nums[i] + nums[k] + nums[p] + nums[q] > target:
q = q -1
elif nums[i] + nums[k] + nums[p] + nums[q] < target:
p = p + 1
else:
res.append([nums[i], nums[k], nums[p], nums[q]])
# 对q和p去重
while p < q and nums[p] == nums[p+1]: p += 1
while p < q and nums[q] == nums[q-1]: q -= 1
p += 1
q -= 1
return res
注意:
- 三数之和的题解与四数之和差不多,但是如果下面还有五个数、六个数就不太适用了,这个时候要考虑其他解法
- 四数之和与四数相加的不同点:四数相加没有要求去重,而且只需要统计次数。但四数之和这道题一定要去重才行。
难点
- 双指针法的使用
总结
最后两题是利用双指针法,没有使用哈希表,也是区别于第一道题的思路。这些题还是经常回顾看看写写,了解的基础上加记忆,要了解去重的过程。