算法: 4数之和到k数之和通用解法18. 4Sum

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


复杂度分析:

  1. fourSum函数:排序的复杂度是O(nlogn)。
  2. kSum函数:递归的调用kSum函数k次,每次递归将长度减小。因此,其复杂度是O(n^k)。
  3. twoSum函数:线性地遍历列表,其复杂度是O(n)。

所以,整体时间复杂度是O(nlogn) + O(n^k),在这种特定情况下,k=4,所以复杂度是O(nlogn + n4)。但是,由于四次方的影响大于logn,可以简化为O(n4)。

空间复杂度为O(n)(由于递归调用和seen集合的存储)。

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/132220973