Skip to content

4Sum II

Problem Statement

Given four integer arrays nums1, nums2, nums3, and nums4 all of length n, return the number of tuples (i, j, k, l) such that:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

LeetCode: 454. 4Sum II

Examples

Example 1:

text
Input: nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
Output: 2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

Example 2:

text
Input: nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
Output: 1

Constraints

  • n == nums1.length == nums2.length == nums3.length == nums4.length
  • 1 <= n <= 200
  • -2^28 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2^28

Two HashMap Approach

4Sum II Visualization

Key Insight

Split the four arrays into two groups. Store all sums from the first group in a hash map, then check if the negation of sums from the second group exists.

Algorithm

  1. Calculate all possible sums of nums1[i] + nums2[j], store in hash map with counts
  2. For each sum nums3[k] + nums4[l], check if -(nums3[k] + nums4[l]) exists in hash map
  3. Add the count from hash map to result

Solution

python
from typing import List
from collections import Counter

def fourSumCount(nums1: List[int], nums2: List[int],
                 nums3: List[int], nums4: List[int]) -> int:
    """
    Count 4-tuples that sum to zero.

    Time: O(n^2) - two nested loops twice
    Space: O(n^2) - hash map for pair sums
    """
    # Store all sums of nums1[i] + nums2[j]
    sum_ab = Counter()
    for a in nums1:
        for b in nums2:
            sum_ab[a + b] += 1

    # Check for complementary sums in nums3, nums4
    count = 0
    for c in nums3:
        for d in nums4:
            target = -(c + d)
            count += sum_ab[target]

    return count
java
import java.util.*;

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> sumAB = new HashMap<>();

        for (int a : nums1) {
            for (int b : nums2) {
                sumAB.merge(a + b, 1, Integer::sum);
            }
        }

        int count = 0;
        for (int c : nums3) {
            for (int d : nums4) {
                count += sumAB.getOrDefault(-(c + d), 0);
            }
        }

        return count;
    }
}

Complexity: Time O(n^2) · Space O(n^2)

  • Time: Two O(n^2) passes: first builds hash map of all AB sums, second checks all CD sums
  • Space: Hash map stores up to n^2 unique sum values with their counts
python
# Alternative: Using defaultdict
from collections import defaultdict

def fourSumCountDefaultDict(nums1: List[int], nums2: List[int],
                            nums3: List[int], nums4: List[int]) -> int:
    """Using defaultdict for clarity."""
    sum_ab = defaultdict(int)

    for a in nums1:
        for b in nums2:
            sum_ab[a + b] += 1

    count = 0
    for c in nums3:
        for d in nums4:
            count += sum_ab.get(-(c + d), 0)

    return count

Complexity: Time O(n^2) · Space O(n^2)

  • Time: Same as Counter approach - two nested loop pairs
  • Space: defaultdict stores same n^2 potential unique sums
python
# One-liner with Counter
def fourSumCountOneLiner(nums1: List[int], nums2: List[int],
                         nums3: List[int], nums4: List[int]) -> int:
    """Concise version using Counter."""
    sum_ab = Counter(a + b for a in nums1 for b in nums2)
    return sum(sum_ab[-c - d] for c in nums3 for d in nums4)

Complexity: Time O(n^2) · Space O(n^2)

  • Time: Generator expressions evaluate n^2 pairs for AB sums, then n^2 lookups for CD
  • Space: Counter stores up to n^2 distinct AB sums

Complexity Analysis

ApproachTimeSpace
Two HashMapO(n^2)O(n^2)
Brute ForceO(n^4)O(1)

Why Split 2+2?

  • Split 1+3: O(n) + O(n^3) = O(n^3) - worse
  • Split 2+2: O(n^2) + O(n^2) = O(n^2) - optimal
  • Split 3+1: O(n^3) + O(n) = O(n^3) - worse

The 2+2 split minimizes the total work.

Edge Cases

  1. All zeros: [0], [0], [0], [0] - Return 1
  2. No valid tuples: Arrays with no combinations summing to 0
  3. Large numbers: May overflow if not careful (use appropriate types)
  4. Duplicate values: Each index counts separately

Variations

K-Sum with K Arrays

python
def kSumCount(arrays: List[List[int]], target: int = 0) -> int:
    """
    Generalized K-Sum for K arrays.
    Split arrays in half for optimal O(n^(k/2)) complexity.
    """
    k = len(arrays)
    if k == 0:
        return 0

    # Split arrays into two halves
    mid = k // 2
    first_half = arrays[:mid]
    second_half = arrays[mid:]

    def get_all_sums(arrs):
        """Get all possible sums from multiple arrays."""
        if not arrs:
            return Counter([0])

        sums = Counter([0])
        for arr in arrs:
            new_sums = Counter()
            for prev_sum, count in sums.items():
                for num in arr:
                    new_sums[prev_sum + num] += count
            sums = new_sums
        return sums

    first_sums = get_all_sums(first_half)
    count = 0

    # Generate second half sums and check
    second_sums = get_all_sums(second_half)
    for s, c in second_sums.items():
        count += first_sums[target - s] * c

    return count

Complexity: Time O(n^(k/2)) · Space O(n^(k/2))

  • Time: Each half generates n^(k/2) sums; matching is linear in the number of sums
  • Space: Hash map for each half stores up to n^(k/2) distinct sums

4Sum (Find All Unique Quadruplets)

python
def fourSum(nums: List[int], target: int) -> List[List[int]]:
    """
    Find all unique quadruplets that sum to target.
    Different from 4Sum II - single array, unique values.

    Time: O(n^3)
    Space: O(1) excluding output
    """
    nums.sort()
    n = len(nums)
    result = []

    for i in range(n - 3):
        # Skip duplicates for first number
        if i > 0 and nums[i] == nums[i - 1]:
            continue

        for j in range(i + 1, n - 2):
            # Skip duplicates for second number
            if j > i + 1 and nums[j] == nums[j - 1]:
                continue

            # Two-pointer for remaining two numbers
            left, right = j + 1, n - 1
            while left < right:
                total = nums[i] + nums[j] + nums[left] + nums[right]

                if total == target:
                    result.append([nums[i], nums[j], nums[left], nums[right]])
                    # Skip duplicates
                    while left < right and nums[left] == nums[left + 1]:
                        left += 1
                    while left < right and nums[right] == nums[right - 1]:
                        right -= 1
                    left += 1
                    right -= 1
                elif total < target:
                    left += 1
                else:
                    right -= 1

    return result

Complexity: Time O(n^3) · Space O(log n) to O(n)

  • Time: Two outer loops O(n^2) with inner two-pointer O(n) each
  • Space: Sorting uses O(log n) to O(n); result space excluded from analysis

3Sum

python
def threeSum(nums: List[int]) -> List[List[int]]:
    """
    Find all unique triplets that sum to zero.

    Time: O(n^2)
    Space: O(1) excluding output
    """
    nums.sort()
    result = []

    for i in range(len(nums) - 2):
        if i > 0 and nums[i] == nums[i - 1]:
            continue

        left, right = i + 1, len(nums) - 1
        while left < right:
            total = nums[i] + nums[left] + nums[right]

            if total == 0:
                result.append([nums[i], nums[left], nums[right]])
                while left < right and nums[left] == nums[left + 1]:
                    left += 1
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1
                left += 1
                right -= 1
            elif total < 0:
                left += 1
            else:
                right -= 1

    return result

Complexity: Time O(n^2) · Space O(log n) to O(n)

  • Time: Sorting O(n log n) plus outer loop O(n) with inner two-pointer O(n) = O(n^2)
  • Space: Sorting uses O(log n) to O(n) depending on implementation

Interview Tips

  1. Clarify the problem: 4Sum II vs 4Sum are different problems
  2. Discuss time complexity: Explain why 2+2 split is optimal
  3. Handle duplicates: This problem counts duplicate indices separately
  4. Consider memory: O(n^2) space might be significant for large n

Common Mistakes

  1. Confusing with 4Sum (single array, unique quadruplets)
  2. Not counting duplicate sums correctly
  3. Using wrong split (1+3 instead of 2+2)
  4. Integer overflow with large numbers
Two Sum (LeetCode 1)

Problem: Find two numbers in array that sum to target.

Key Insight: Use hash map to store values and check for complements in one pass.

Approach: For each num, check if complement exists. If not, store current num with index.

Complexity: Time O(n), Space O(n)

3Sum (LeetCode 15)

Problem: Find all unique triplets that sum to zero.

Key Insight: Sort array, fix one element, use two-pointer for remaining.

Approach: For each i, use two pointers from i+1 and end. Skip duplicates.

Complexity: Time O(n^2), Space O(1) extra

4Sum (LeetCode 18)

Problem: Find all unique quadruplets in single array summing to target.

Key Insight: Unlike 4Sum II, requires unique quadruplets from one array. Use two loops + two-pointer.

Approach: Two outer loops fix first two elements. Two-pointer finds remaining two.

Complexity: Time O(n^3), Space O(1) extra

Two Sum II - Input Array Is Sorted (LeetCode 167)

Problem: Find two numbers in sorted array summing to target.

Key Insight: Sorted array allows two-pointer approach, no hash map needed.

Approach: Left and right pointers, move based on sum comparison with target.

Complexity: Time O(n), Space O(1)