18. 4Sum Medium
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 < na,b,c, anddare 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]]
Approach
Input: An integer array nums, a target integer.
Output: Find all unique quadruplets [a, b, c, d] that satisfy a + b + c + d == target.
This is a classic problem of sorting + opposite-direction two pointers.
This problem's solution is similar to 3Sum. We can sort the array first, then fix two numbers nums[a] and nums[b], and then use two pointers in the range b+1 to n-1.
Essentially, after fixing the two numbers nums[a] and nums[b], we refer to finding two other values such that the sum of the four numbers is target.
Implementation
from typing import List
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort() # Sort first, helpful for deduplication and two pointers
n = len(nums)
res = []
for a in range(n - 3):
# Skip duplicate elements
if a > 0 and nums[a] == nums[a - 1]:
continue
# Pruning: The sum of the smallest four numbers is already greater than target, no need to continue
if nums[a] + nums[a + 1] + nums[a + 2] + nums[a + 3] > target:
break
# Pruning: The current fixed number plus the sum of the largest three numbers is less than target, skip current
if nums[a] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target:
continue
for b in range(a + 1, n - 2):
# Skip duplicate elements
if b > a + 1 and nums[b] == nums[b - 1]:
continue
# Pruning: The current a, b are fixed, and the sum with the next two smallest numbers is greater than target
if nums[a] + nums[b] + nums[b + 1] + nums[b + 2] > target:
break
# Pruning: The current a, b are fixed, and the sum with the next two largest numbers is less than target
if nums[a] + nums[b] + nums[n - 1] + nums[n - 2] < target:
continue
# Two pointers to find the other two numbers
left, right = b + 1, n - 1
while left < right:
total = nums[a] + nums[b] + nums[left] + nums[right]
if total == target:
res.append([nums[a], nums[b], nums[left], nums[right]])
left += 1
right -= 1
# Skip duplicate elements
while left < right and nums[left] == nums[left - 1]:
left += 1
while left < right and nums[right] == nums[right + 1]:
right -= 1
elif total < target:
left += 1
else:
right -= 1
return res/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
nums.sort((a, b) => a - b); // Sort the array first for easier deduplication and two-pointer operations
const res = [];
const n = nums.length;
for (let a = 0; a < n - 3; a++) {
// Skip duplicates to prevent duplicate results
if (a > 0 && nums[a] === nums[a - 1]) continue;
// Pruning: the minimum possible value has already exceeded target, impossible to meet the condition afterwards
if (nums[a] + nums[a + 1] + nums[a + 2] + nums[a + 3] > target) break;
// Pruning: the current value plus the largest three numbers is still less than target, skip current
if (nums[a] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target) continue;
for (let b = a + 1; b < n - 2; b++) {
// Skip duplicates
if (b > a + 1 && nums[b] === nums[b - 1]) continue;
// Pruning: the minimum possible value under the current combination exceeds target
if (nums[a] + nums[b] + nums[b + 1] + nums[b + 2] > target) break;
// Pruning: the maximum possible value under the current combination is still less than target
if (nums[a] + nums[b] + nums[n - 1] + nums[n - 2] < target) continue;
let left = b + 1;
let right = n - 1;
while (left < right) {
const sum = nums[a] + nums[b] + nums[left] + nums[right];
if (sum === target) {
res.push([nums[a], nums[b], nums[left], nums[right]]);
// Skip the duplicate 3rd number
while (left < right && nums[left] === nums[left + 1]) left++;
left++;
// Skip the duplicate 4th number
while (left < right && nums[right] === nums[right - 1]) right--;
right--;
} else if (sum < target) {
left++; // Total sum is too small, move left pointer to the right
} else {
right--; // Total sum is too large, move right pointer to the left
}
}
}
}
return res;
};Complexity Analysis
- Time Complexity: O(n^3)
- Space Complexity: O(1)