18. 4Sum
Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:
- 0 <= a, b, c, d < n
- a, b, c, and d are distinct.
- nums[a] + nums[b] + nums[c] + nums[d] == target
You may return the answer in any order.
Example 1:
Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
Example 2:
Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]
Constraints:
- 1 <= nums.length <= 200
- -109 <= nums[i] <= 109
- -109 <= target <= 109
通用解法为k数之和
解决“4数之和”问题,即寻找四个数字,使它们的和等于目标值。它使用了更一般的kSum函数来解决k数之和问题,并使用了一个特定的twoSum函数来处理2数之和的特例。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort() # 排序输入数组
return self.kSum(nums, target, 4) # 查找四个数字的和等于目标值的所有组合
def kSum(self, nums, target, k) -> List[List[int]]:
res = []
if not nums: # 如果nums为空,直接返回空列表
return res
# 两个数之和的特殊情况
if k == 2:
return self.twoSum(nums, target)
avg = target / k # 计算平均值
# 如果最小值大于平均值或最大值小于平均值,则没有合适的组合
if nums[0] > avg or nums[-1] < avg:
return res
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]: # 跳过重复的数字
continue
# 对于当前数字,寻找k-1个数字的和等于target-nums[i]的组合
for subset in self.kSum(nums[i+1:], target-nums[i], k-1):
res.append([nums[i]] + subset)
return res
def twoSum(self, nums, target) -> List[List[int]]:
res = []
seen = set() # 用于存储已经遍历过的数字
lo = 0
n = len(nums)
while lo < n:
if nums[lo] in seen: # 如果数字在seen中,则找到一个解
res.append([target - nums[lo], nums[lo]])
while lo+1 < n and nums[lo] == nums[lo+1]: # 跳过重复的数字
lo += 1
seen.add(target - nums[lo])
lo += 1
return res
复杂度分析:
- fourSum函数:排序的复杂度是O(nlogn)。
- kSum函数:递归的调用kSum函数k次,每次递归将长度减小。因此,其复杂度是O(n^k)。
- twoSum函数:线性地遍历列表,其复杂度是O(n)。
所以,整体时间复杂度是O(nlogn) + O(n^k),在这种特定情况下,k=4,所以复杂度是O(nlogn + n4)。但是,由于四次方的影响大于logn,可以简化为O(n4)。
空间复杂度为O(n)(由于递归调用和seen集合的存储)。