0018. Four Sum

0018. Four Sum#

Problem#

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.

Examples#

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

Analysis#

Trs is similar to 0015.

Solution#

# Solution 1: two pointer 
def solution(nums, target=0):
    nums.sort()
    res = [] 

    for h, a in enumerate(nums[:-3]):
        if h > 0 and a == nums[h - 1]: # if duplicate, pass
            continue
        # 3 sum
        nums3 = nums[h+1:]
        sum3_target = target - nums[h]
        for i, b in enumerate(nums3):
            if i > 0 and b == nums3[i - 1]: # if duplicate, pass
                continue
            # 2 sum
            j, k = i+1, len(nums3)-1
            sum2_target = sum3_target - nums3[i]
            while j < k:
                if nums3[j] + nums3[k] < sum2_target:
                    j += 1
                elif nums3[j] + nums3[k] > sum2_target:
                    k += -1
                else:
                    res.append([nums[h], nums3[i], nums3[j], nums3[k]])
                    j += 1
                    while nums3[j] == nums3[j-1] and j < k: # skip duplicates
                        j += 1
    return res

# test
nums = [1,0,-1,0,-2,2]
target = 0
print(solution(nums))
[[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]
# solution 2: k-sum
def solution(nums, target):

    def kSum(nums, target,  k):
        res = []
        
        # If we have run out of numbers to add, return res.
        if not nums:
            return res
        
        # There are k remaining values to add to the sum. The 
        # average of these values is at least target // k.
        average_value = target // k
        
        # We cannot obtain a sum of target if the smallest value
        # in nums is greater than target // k or if the largest 
        # value in nums is smaller than target // k.
        if average_value < nums[0] or nums[-1] < average_value:
            return res
        
        if k == 2:
            return twoSum(nums, target)

        for i in range(len(nums)):
            if i == 0 or nums[i - 1] != nums[i]:
                for subset in kSum(nums[i + 1:], target - nums[i], k - 1):
                    res.append([nums[i]] + subset)

        return res

    def twoSum(nums, target):
        res = []
        l, r = 0, len(nums) - 1

        while (l < r):
            curr_sum = nums[l] + nums[r]
            if curr_sum < target or (l > 0 and nums[l] == nums[l - 1]):
                l += 1
            elif curr_sum > target or (r < len(nums) - 1 and nums[r] == nums[r + 1]):
                r -= 1
            else:
                res.append([nums[l], nums[r]])
                l += 1
                r -= 1
                                                        
        return res

    nums.sort()
    return kSum(nums, target, 4)

# test
nums = [1,0,-1,0,-2,2]
target = 0
print(solution(nums, target))
[[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]