454. 四数相加 II
思路:将四数相加看做是高阶的两数之和
首先遍历求解nums1和nums2的和,并将其放在字典unordered_map {nums[i] + nums[j] : 出现频次}
中,随后遍历nums3和nums4查看0 -(nums3 + nums4)
是否在unordered_map
中,设置一个cnt
用于计数在unordered_map
中出现的次数。
注意
这里并不需要对结果去重,少了去重的一步,因此比较简单,只需要对出现过的元组次数累加即可。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
unordered_map = {}
for i in range(len(nums1)):
for j in range(len(nums2)):
sum = nums1[i] + nums2[j]
unordered_map[sum] = unordered_map.get(sum, 0) + 1
cnt = 0
for i in range(len(nums3)):
for j in range(len(nums4)):
sum = nums3[i] + nums4[j]
need = 0 - sum
if need in unordered_map:
cnt += unordered_map[need]
return cnt
383. 赎金信
思路
- 目标:判断 ransomNote 能不能由 magazine 里面的字符。
- 方法:遍历 ransomNote 并检查 magazine 中是否有所有字母;因此需要将 magazine 中的字符串整理为{字母:频次}的hash table。
注意
- 第二个遍历时,要注意hash_table中有这个key但是value已经为0的情况。
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
# 判断 ransomNote 能不能由 magazine 里面的字符
# 遍历 ransomNote 并检查 magazine 中是否有所有字母
# 因此需要将 magazine 中的字符串整理为{字母:频次}的hash table
hash_table = {}
for i in magazine:
hash_table[i] = hash_table.get(i, 0) + 1
for j in ransomNote:
# 注意要在这里检查频次是否为0
if j in hash_table and hash_table[j]:
hash_table[j] = hash_table.get(j) - 1
else:
return False
return True
15. 三数之和
算法:双指针法
- 失败的去重操作:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 将数组排序之后用双指针法解决
nums.sort()
res = []
i = 0
# 下面的这个应该放在循环的代码中不然left和right每次不能复位
left = i + 1
right = len(nums) - 1
# 应该有一个for循环来驱动i的变化 内部有while循环驱动left和right的变化
while True:
# 判断三数之和
if nums[i] + nums[left] + nums[right] == 0:
res.append([nums[i], nums[left], nums[right]])
elif nums[i] + nums[left] + nums[right] > 0:
right -= 1
else:
left += 1
# 去重
# a的去重
# 并没有设置i的右边界,并且当i取len(nums)-1时nums[i+1]会溢出
if nums[i] == nums[i+1]:
i += 2
i += 1
# b的去重
left = i + 1
if nums[left] == nums[left+1]:
# 去重时应该是只要还相等就一直往前移动一个位置
left += 2
left += 1
# c的去重
if nums[left] < nums[right] and nums[right] == nums[right-1]:
right -= 2
right -= 1
if i == len(nums) - 1 or nums[left] > nums[right]:
return res
- 正确版本
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 将数组排序之后用双指针法解决
nums.sort()
res = []
for i in range(len(nums)):
left = i + 1
right = len(nums) - 1
# a的剪枝
if nums[i] > 0:
return res
# a的去重
if i >= 1 and nums[i] == nums[i-1]:
continue
while left < right:
# 求解三数之和
sum = nums[i] + nums[left] + nums[right]
if sum == 0:
res.append([nums[i], nums[left], nums[right]])
# 新增元素之后需要去重 以跳过重复的元素
# b的去重 只要相等且左边小于右边则一直移动
while left < right and nums[left] == nums[left+1]:
left += 1
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
right -= 1
elif sum < 0:
left += 1
else:
right -= 1
return res
18. 四数之和
方法:双指针法
在三数之和的基础上,在最外面加一个for循环,就可以得到四数之和,另外,五数之和,六数之和,均是同样的套路。
值得注意的是,对a和b剪枝时,不能简单地return,并且剪枝的条件不是单纯的>target (要考虑负数的可能性)。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(n):
if nums[i] > target and nums[i] > 0 and target > 0:
break
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, n):
if nums[i] + nums[j] > target and target > 0:
break
if j > i+1 and nums[j] == nums[j-1]:
continue
left, right = j+1, n-1
while left < right:
s = nums[i] + nums[j] + nums[left] + nums[right]
if s == target:
res.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
elif s < target:
left += 1
else:
right -= 1
return res
两数之和-哈希法;三数之和-双指针法;四数之和(三数之和+外层for循环);