454. 四数相加 II
题目链接:力扣454
思路:哈希表
本题仅仅是四个数组里的元素值相加等于0,不需要考虑元素数值或下标重复的情况,类似于两数之和。
用变量cnt存储最终符合的元组个数,变量record为哈希表。
两层for循环扫描L1和L2,用key存储每一项L1+L2的数值,用value存储该数值出现次数。
两层for循环扫描L3和L4,在map中寻找对应的-(L3+L4),找到后令cnt加上该项的value值。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
record = {}
cnt = 0
for i in nums1:
for j in nums2:
if i+j in record.keys():
record[i+j] += 1
else:
record[i+j] = 1
for i in nums3:
for j in nums4:
target = 0-i-j
if target in record.keys():
cnt += record[target]
return cnt
383. 赎金信
题目链接:力扣383
思路:哈希表
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
record = [0]*26
for i in magazine:
record[ord(i) - ord('a')] += 1
for i in ransomNote:
record[ord(i) - ord('a')] -= 1
for i in record:
if i < 0:
return False
return True
15. 三数之和
题目链接:力扣15
思路:双指针
本题需要考虑元组重复的情况,比如[-1,0,1]和[0,1,-1]算一个三元组,使用哈希表较为麻烦,使用双指针。
双指针大体流程:
①先对数组排序。
②进入for循环:
i在数组下标0处,设置好左右指针。
最终三元组为[ nums[i], nums[left], nums[right] ],这里简写为(a,b,c)。
用for循环用来固定三元组第一个元素,左右指针用于寻找能满足相加等于0的后两个元素
需要先对a去重,检查i前面一个元素是否与当前相同,相同则continue
判断nums[i] + nums[left] + nums[right]大小,若大于0,说明该三元组“小”了,左指针向右移动,使三元组和变小。
若大于0,向左移动右指针。
最后直至三元组之和为0(如下),或者left>=right结束当前while循环,i++进入下一次for循环。
此时收割结果,[-3, 1, 2]放入res数组中。
③同时,需要对left和right去重,因为在当前for循环,当前i的值下,left和right对应的数组元素值已经“用过了”,需要left和right分别向右向左走实现去重=,去重后如下。
去重的原因是题目要求三元组不能重复,一个三元组只能出现一次。
以左指针为例,这里去重本质上就是让左指针走到最靠右的,与之前元素值相同的位置处。
同时,若本次while若找到目标,无论前面是否需要去重,左右指针还需再收缩一次。
在示例中收缩完后left>right,while结束,进入下一次for循环。
# 涉及到去重操作,哈希表较为麻烦,使用双指针
# 答案格式为数组元素组成的三元组(a,b,c)
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res=[]
for i in range(len(nums)):
if nums[i] > 0:
break
if i>0 and nums[i] == nums[i-1]: # 三元组a去重
continue
left = i+1
right = len(nums)-1
while left < right:
if nums[i] + nums[left] + nums[right] < 0: # 说明当前三元组“小”了
left += 1
elif nums[i] + nums[left] + nums[right] > 0: # 说明当前三元组“大”了
right -= 1
else: #满足条件时
res.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]: #b去重,注意这里仍要保证left<right
left += 1
while left < right and nums[right] == nums[right-1]: #c去重
right -= 1
# 找到答案后双指针在去重完后需要收缩一次
right -= 1
left +=1
return res
18. 四数之和
题目链接:力扣18
思路:双指针
与上一题思路类似,又套一层for循环而已,两层for循环分别固定四数之和里的前两个数。
注意k和i的去重。
注意k大于target时的剪枝。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
res = []
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 i>k+1 and nums[i] == nums[i-1]: # 注意这里的条件,i-1不能影响到k的取值,所以要i>k+1
continue
left = i+1
right = len(nums)-1
while left < right:
total = nums[k]+nums[i]+nums[left]+nums[right]
if total>target:
right -= 1
elif total<target:
left += 1
else:
res.append([nums[k], 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 res