题目描述:
给你一个由 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]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
提示:
1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
LeetCode链接:leetcode18
思路分析:
这道题可以借用哈希表第8/9题--三数之和的部分代码,思路也是双指针。区别在于这里是需要找出四元组,并且和不是0,而是一个固定的target,这个target可以为负数,0或者正数。所以在剪枝的时候需要注意区分;
解法的第一步也是对列表进行排序,使用列表的内置sort函数进行;
然后分别设置四个下标代表这四个数,分别为i, j, left, right。首先循环i,对其进行剪枝,当满足nums[i]>target and target>0 这两个条件时,直接退出。这是为什么呢?前面三数之和的时候不是只有nums[i]>0这一个条件吗?这是因为前面三数之和target=0,而排序之和如果最小的数nums[i]>0,说明不可能满足条件了。但是这题的target可能为负数,比如nums=[-4,-3, -2, -1, 0, 0,4],假设target = -3,那么[-2,-1, 0, 0]也是满足的,此时nums[i]==-2 > target, 如果按nums[i]>target 这一条的话这个结果就被删了,这显然是不行的。所以需要再加限定条件将剪枝范围缩小,将nums[i]>0这条加上,就排除了nums[i]==负数这一情况。
然后对j进行剪枝并去重,j是从i+1开始循环增加1,当j有重复值时,跳过。left=j+1, right=n-1;
对j进行循环加1,当left<right时,s= nums[i]+ nums[j]+ nums[left]+ nums[right], 当s=target时,产生符合条件的四元组,添加到result中,并对left和right进行去重,过程同三数之和。
代码分析:
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
result = []
for i in range(n):
if nums[i] > target 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:
result.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 result