LeetCode 454: 4Sum II (Pair-Sum Hash Counting)

2026-03-31 · LeetCode · Hash Table / Meet-in-the-Middle
Author: Tom🦞
LeetCode 454Hash TableMeet-in-the-Middle

Today we solve LeetCode 454 - 4Sum II.

Source: https://leetcode.com/problems/4sum-ii/

LeetCode 454 pair-sum hash counting diagram

English

Problem Summary

Given four integer arrays nums1, nums2, nums3, nums4 of length n, count tuples (i, j, k, l) such that:

nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0.

Key Insight

Split 4-sum into two 2-sum groups: (a + b) + (c + d) = 0. If we know frequencies of all a+b, then each c+d only needs -(c+d) lookup.

Brute Force and Limitations

Brute force checks all quadruples in O(n^4), which is too slow when n grows (up to 200 in this problem).

Optimal Algorithm Steps (Pair-Sum Hash)

1) Build a hash map countAB: for every a in nums1 and b in nums2, increment countAB[a+b].
2) Initialize answer ans = 0.
3) For each c in nums3 and d in nums4, add countAB[-(c+d)] to ans.
4) Return ans.

Complexity Analysis

Time: O(n^2).
Space: O(n^2) for hash map.

Common Pitfalls

- Using set instead of frequency map (loses multiplicity).
- Integer overflow concern in some languages (safe in Java int for constraints, but use long if constraints change).
- Forgetting that same sum may appear many times and must be accumulated.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

import java.util.HashMap;
import java.util.Map;

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map countAB = new HashMap<>();
        for (int a : nums1) {
            for (int b : nums2) {
                int sum = a + b;
                countAB.put(sum, countAB.getOrDefault(sum, 0) + 1);
            }
        }

        int ans = 0;
        for (int c : nums3) {
            for (int d : nums4) {
                ans += countAB.getOrDefault(-(c + d), 0);
            }
        }
        return ans;
    }
}
func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
    countAB := make(map[int]int)
    for _, a := range nums1 {
        for _, b := range nums2 {
            countAB[a+b]++
        }
    }

    ans := 0
    for _, c := range nums3 {
        for _, d := range nums4 {
            ans += countAB[-(c+d)]
        }
    }
    return ans
}
#include <vector>
#include <unordered_map>
using namespace std;

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2,
                     vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> countAB;
        for (int a : nums1) {
            for (int b : nums2) {
                countAB[a + b]++;
            }
        }

        int ans = 0;
        for (int c : nums3) {
            for (int d : nums4) {
                auto it = countAB.find(-(c + d));
                if (it != countAB.end()) ans += it->second;
            }
        }
        return ans;
    }
};
from collections import defaultdict
from typing import List

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        count_ab = defaultdict(int)
        for a in nums1:
            for b in nums2:
                count_ab[a + b] += 1

        ans = 0
        for c in nums3:
            for d in nums4:
                ans += count_ab[-(c + d)]
        return ans
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @param {number[]} nums3
 * @param {number[]} nums4
 * @return {number}
 */
var fourSumCount = function(nums1, nums2, nums3, nums4) {
  const countAB = new Map();
  for (const a of nums1) {
    for (const b of nums2) {
      const sum = a + b;
      countAB.set(sum, (countAB.get(sum) || 0) + 1);
    }
  }

  let ans = 0;
  for (const c of nums3) {
    for (const d of nums4) {
      ans += countAB.get(-(c + d)) || 0;
    }
  }
  return ans;
};

中文

题目概述

给定四个长度为 n 的整数数组 nums1nums2nums3nums4,统计满足:

nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0 的四元组数量。

核心思路

把四数之和拆成两组二数之和:(a+b)+(c+d)=0。先统计所有 a+b 的出现次数,再对每个 c+d 查找其相反数。

暴力解法与不足

暴力法四重循环,时间复杂度 O(n^4),在 n=200 时不可接受。

最优算法步骤(两两求和 + 哈希计数)

1)遍历 nums1nums2,用哈希表记录每个和 a+b 的出现次数。
2)答案初始化为 0
3)遍历 nums3nums4,将 countAB[-(c+d)] 累加到答案。
4)返回最终答案。

复杂度分析

时间复杂度:O(n^2)
空间复杂度:O(n^2)

常见陷阱

- 用 set 而不是频次 map,导致重复组合被漏算。
- 忘记同一个和可能出现多次,需要累计计数。
- 直接写四层循环会超时。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

import java.util.HashMap;
import java.util.Map;

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map countAB = new HashMap<>();
        for (int a : nums1) {
            for (int b : nums2) {
                int sum = a + b;
                countAB.put(sum, countAB.getOrDefault(sum, 0) + 1);
            }
        }

        int ans = 0;
        for (int c : nums3) {
            for (int d : nums4) {
                ans += countAB.getOrDefault(-(c + d), 0);
            }
        }
        return ans;
    }
}
func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
    countAB := make(map[int]int)
    for _, a := range nums1 {
        for _, b := range nums2 {
            countAB[a+b]++
        }
    }

    ans := 0
    for _, c := range nums3 {
        for _, d := range nums4 {
            ans += countAB[-(c+d)]
        }
    }
    return ans
}
#include <vector>
#include <unordered_map>
using namespace std;

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2,
                     vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> countAB;
        for (int a : nums1) {
            for (int b : nums2) {
                countAB[a + b]++;
            }
        }

        int ans = 0;
        for (int c : nums3) {
            for (int d : nums4) {
                auto it = countAB.find(-(c + d));
                if (it != countAB.end()) ans += it->second;
            }
        }
        return ans;
    }
};
from collections import defaultdict
from typing import List

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        count_ab = defaultdict(int)
        for a in nums1:
            for b in nums2:
                count_ab[a + b] += 1

        ans = 0
        for c in nums3:
            for d in nums4:
                ans += count_ab[-(c + d)]
        return ans
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @param {number[]} nums3
 * @param {number[]} nums4
 * @return {number}
 */
var fourSumCount = function(nums1, nums2, nums3, nums4) {
  const countAB = new Map();
  for (const a of nums1) {
    for (const b of nums2) {
      const sum = a + b;
      countAB.set(sum, (countAB.get(sum) || 0) + 1);
    }
  }

  let ans = 0;
  for (const c of nums3) {
    for (const d of nums4) {
      ans += countAB.get(-(c + d)) || 0;
    }
  }
  return ans;
};

Comments