18. 四数之和
Posted 炫云云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18. 四数之和相关的知识,希望对你有一定的参考价值。
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
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
排序 + 双指针
使用双循环固定两个数,用双指针找另外两个数,通过比较与target
的大小,移动指针。
假设两重循环枚举到的前两个数分别位于下标 i i i 和 j j j ,其中 i < j i<j i<j 。初始时,左右指针分别指向下标 j + 1 j+1 j+1 和下标 n − 1 n-1 n−1。 每次计算四个数的和,并进行如下操作:
- 如果和等于
target
\\textit{target}
target ,则将枚举到的四个数加到答案中, 执行
left += 1
和right -= 1
并跳过所有重复的nums[left]
和nums[right]
,防止记录到重复组合。 - 如果和小于
target
\\textit{target}
target ,则
left += 1
; - 如果和大于
target
\\textit{target}
target ,则
right -= 1
;
具体实现时,还可以进行一些剪枝操作:
- 在确定第一个数之后,如果 nums [ i ] + nums [ i + 1 ] + nums [ i + 2 ] + nums [ i + 3 ] > target \\textit{nums}[i]+\\textit{nums}[i+1]+\\textit{nums}[i+2]+\\textit{nums}[i+3]>\\textit{target} nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target,说明此时剩下的三个数无论取什么值,四数之和一定大于 target \\textit{target} target ,因此退出第一重循环;
- 在确定第一个数之后,如果 nums [ i ] + nums [ n − 3 ] + nums [ n − 2 ] + nums [ n − 1 ] < target \\textit{nums}[i]+\\textit{nums}[n-3]+\\textit{nums}[n-2]+\\textit{nums}[n-1]<\\textit{target} nums[i]+nums[n−3]+nums[n−2]+nums[n−1]<target ,说明此时剩下的三个数无论取什么值,四数之和一定小于 target , \\textit{target} , target,因此第一重循环直接进入下一轮,枚举 nums [ i + 1 ] \\textit{nums}[i+1] nums[i+1] ;
- 在确定前两个数之后,如果 nums [ i ] + nums [ j ] + nums [ j + 1 ] + nums [ j + 2 ] > target \\textit{nums}[i]+\\textit{nums}[j]+\\textit{nums}[j+1]+\\textit{nums}[j+2]>\\textit{target} nums[i]+nums[j]+nums[j+1]+nums[j+2]>target,说明此时剩下的两个数无论取什么值,四数之和一定大于 target \\textit{target} target ,因此退出第二重循环;
- 在确定前两个数之后,如果 nums [ i ] + nums [ j ] + nums [ n − 2 ] + nums [ n − 1 ] < target \\textit{nums}[i]+\\textit{nums}[j]+\\textit{nums}[n-2]+\\textit{nums}[n-1]<\\textit{target} nums[i]+nums[j]+nums[n−2]+nums[n−1]<target ,说明此时剩下的两个数无论取什么值,四数之和一定小于 target \\textit{target} target ,因此第二重循环直接进入下一轮,枚举 nums [ j + 1 ] \\textit{nums}[j+1] nums[j+1] 。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
quadruplets = list() # 定义一个返回值
if not nums or len(nums) < 4:
return quadruplets
nums.sort()
length = len(nums)
# 定义4个指针i,j,left,right i从0开始遍历,j从i+1开始遍历,留下left和right作为双指针
for i in range(length - 3):
if i > 0 and nums[i] == nums[i - 1]: # 当i的值与前面的值相等时忽略
continue
# 获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏
if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target:
break # 这里使用的break,直接退出此次循环,因为后面的数只会更大
# 获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略
if nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target:
continue # 这里使用continue,继续下一次循环,因为下一次循环有更大的数
# 第二层循环j,初始值指向i+1
for j in range(i + 1, length - 2):
if j > i + 1 and nums[j] == nums[j - 1]: # 当j的值与前面的值相等时忽略
continue
if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:
break
if nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target:
continue
left, right = j + 1, length - 1
# 双指针遍历,如果等于目标值,left++并去重,right--并去重,
# 当当前和大于目标值时right--,当当前和小于目标值时left++
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total == target:
quadruplets.append([nums[i], nums[j], nums[left], nums[right]])
left += 1 # left先+1之后,和它前面的left-1进行比较,若后+1,则和它后面的left+1进行比较
right -= 1
while left < right and nums[left] == nums[left - 1]:
left += 1
while left < right and nums[right] == nums[right + 1]:
right -= 1
elif total < target:
left += 1
else:
right -= 1
return quadruplets
参考
以上是关于18. 四数之和的主要内容,如果未能解决你的问题,请参考以下文章