题目描述
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
解题思路一
参考2数之和、3数之和的解题思路,采用多指针方法遍历整个数组。问题转化,通过固定指针将问题模型转化为两数之和,然后利用两数之和的解法进行求解。
因为要求4数之和,所以要先固定2个指针。
(0)数组排序
(1)固定第一个指针p
if nums[p] + 3 * nums[p+1] > target:
break
如果当前指针指向值加上3倍下一位数组的值大于target,终止搜寻。
这是因为数组是排好序的,如果满足了上述条件,是找不到四个数满足相加等于target。
if nums[p] + 3* nums[-1] < target:
while p < n-4 and nums[p] == nums[p+1]:
p += 1
p += 1
continue
如果当前指针指向的值加上3倍的数组最大元素仍然小于target,说明p指向的值太小,要向右移动,
同时,while循环跳过相同的元素,p < n-4 即 p < n - 3 -1 要找到4个数,所以p的最大位置就是
n-3,再减去1是要保证nums[p+1]有值。while循环跳过时nums[p] != nums[p+1],固定p+1
位置,寻找剩下的数据。
外循环也是while结构,所以这里的continue还是从p+1位置开始的,如果是for循环,则p的自加操作
要省去。
(2)固定第二个指针k,k从p的下一个位置开始
# k 从p的下一个位置开始
k = p + 1
# 固定k之后,还有2个数据要查找,所以k的最大位置是n-2
while k < n-2:
# 与p做相同的判断以及去重操作
if nums[p] + nums[k] + 2 * nums[k+1] > target:
break
if nums[p] + nums[k] + 2 * nums[-1] < target:
while k < n - 3 and nums[k] == nums[k+1]:
k += 1
k += 1
continue
(3)固定p、k指针后,问题模型就变成了查找两数之和
i = k + 1 # 左指针
j = n - 1 # 右指针
while i < j:
if nums[i] + nums[j] > new_target:
j -= 1
elif nums[i] + nums[j] < new_target:
i += 1
else:
res.append([nums[p],nums[k],nums[i],nums[j]])
i += 1
j -= 1
while i < j and nums[i] == nums[i-1]: i += 1 # 去重
while i < j and nums[j] == nums[j+1]: j-=1 # 去重
(4)完整代码
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
p = 0
while p < n - 3:
if nums[p] + 3 * nums[p+1] > target:
break
if nums[p] + 3 * nums[-1] < target:
while p < n - 4 and nums[p] == nums[p+1]:
p += 1
p += 1
continue
k = p + 1
while k < n - 2:
if nums[p] + nums[k] + 2 * nums[k+1] > target:
break
if nums[p] + nums[k] + 2 * nums[-1] < target:
while k < n - 3 and nums[k] == nums[k+1]:
k += 1
k += 1
continue
i = k + 1
j = n - 1
new_target = target - nums[p] - nums[k]
while i < j:
if nums[i] + nums[j] > new_target:
j -= 1
elif nums[i] + nums[j] < new_target:
i += 1
else:
res.append([nums[p],nums[k],nums[i],nums[j]])
i += 1
j -= 1
while i < j and nums[i] == nums[i-1]: i += 1
while i < j and nums[j] == nums[j+1]: j-=1
while k < n - 3 and nums[k] == nums[k+1]:k+=1 # 去重
k += 1
while p < n - 4 and nums[p] == nums[p+1]:p+=1 # 去重
p += 1
return res
解题思路二
依然是参考2数之和、三数之和解法,引入字典。
直接上代码
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
res = []
#hash_map = {}
nums.sort()
res_hash = {}
hash_map = {x:i for i,x in enumerate(nums)}
if len(nums) < 4:
return res
for i,first in enumerate(nums):
if i > 0 and nums[i-1] == first:continue
for j,second in enumerate(nums[i+1:]):
if j > 0 and second == nums[i+1+j-1]:continue
for k,third in enumerate(nums[i+1+j+1:]):
curr = first + second + third
if target - curr in hash_map:
fourth_index = hash_map[target-curr]
if fourth_index == i or fourth_index == i+1+j or fourth_index == i+1+j+1+k:
continue
row = sorted([first,second,third,nums[fourth_index]])
"""
key = ''.join([str(x) for x in row])
if key not in res_hash:
res.append(row)
res_hash[key] = True
"""
if row not in res:
res.append(row)
return res
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum