454 四数相加II
思路:
注意: 什么时候需要去重, 什么时候不需要: 之前的4sum 和3sum都是在同一个array中,然后题目要求unique的组合, 所以需要去重。但是这里是在不同的数组中找出组合,所以不需要去重。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
# 这道题要看a + b + c + d = 0, 有多少个组合
# 因为是在不同的subarray中定位, 所以不需要像在同一个array中找index那样去重
# a + b = -(c + d)
# 创建用哈希映射来存储 a+b的结果和其频次
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
if n1 + n2 in hashmap:
hashmap[n1+n2] += 1
else:
hashmap[n1+n2] = 1
# 如果 -(a+b) 在nums3 和 nums4中, count += hashmap[key]
count = 0
for n3 in nums3:
for n4 in nums4:
key = -(n3 + n4)
if key in hashmap:
count += hashmap[key] # 为什么这里是 + value呢, 因为
# a[1] + b[2] = 5
# a[2] + b[3] = 5
# a[3] + b[4] = 5,
# 然后c[1] + b[2] = -5, 在hashmap中 上面的5出现了3遍
# 这会有3个组合满足四个数相加 = 0, 所以count加的是hashmap中的value, 就是出现的次数
return count
15. 三数之和
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 用2 pointer的思路,nums[i] + left + right = 0, 注意不能有重复的组合,所以去重很重要
nums = sorted(nums)
ret = [] # 2d array 存最后的unique 组合
for i in range(len(nums)):
if nums[i] > 0:
return ret # nums是升序排序, 如果第一个数已经>0了,后面的数肯定都大于第一个, 那么不可能相加还=0了
# 当 i 不为第一个数, 当前的数和前面的数一样的话, 就跳过,
if( i > 0 and nums[i] == nums[i-1]): # 这里为什么不是 nums[i] == nums[i+1] 比较呢,因为如果i和i+1相等就跳过的话就会丢失-1,-1,2这种组合
continue #跳过
l = i + 1
r = len(nums) - 1
while (l < r):# l 不能等于 r, 因为当l = r 的时候, 他们都指向的同一个数, 但我们需要两个数 和nums[i] 拼凑
if (nums[i] + nums[l] + nums[r] < 0):
l+=1 # 左边太小了, 要增大
elif (nums[i]+ nums[l] + nums[r] > 0):
r -= 1 # 右边太大了,减小
else:
ret.append([nums[i], nums[l], nums[r]])
# 同理: 万一是 0,-1,-1,-1,1,1,1 的情况,得对l 和r进行去重
while (l < r and nums[l] == nums[l+1]): #l 向右跳
l += 1
while (l < r and nums[r] == nums[r-1]): # r向左跳
r -= 1
r -= 1
l += 1
# print(ret)
# print('null')
return ret
18.四数之和
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
ret = []
# 概念图
# [1,0,-1,0,-2,2]
# k i L R
for k in range(len(nums)):
# 一级剪枝:
if(nums[k]>target and nums[k] > 0 and target > 0 ):
break
# 一级去重
if k > 0 and nums[k] == nums[k - 1]:
continue
for i in range(k+1, len(nums)):
#二级剪枝
if nums[k] + nums[i] > target and target > 0 and nums[k] + nums[i] > 0:
break
# 二级去重
if( i > k + 1 and nums[i] == nums[i-1]):
continue
# 和3sum一样的挪l和r使四数之和 = target, 然后l和r要去重
l = i + 1
r = len(nums) - 1
while l < r:
s = nums[k] + nums[i] + nums[l] + nums[r]
if s == target:
ret.append([nums[k], nums[i], nums[l], nums[r]])
while l < r and nums[l] == nums[l+1]:
l += 1
while l < r and nums[r] == nums[r-1]:
r -= 1
l += 1
r -= 1
elif s < target:
l += 1
else:
r -= 1
# print(ret)
return ret