Skip to main content

15. 3Sum

mediumAsked at JPMorgan

Find all unique triplets (a, b, c) in an integer array such that a + b + c = 0. JPMorgan asks this on SDE onsites as the natural Two-Sum follow-up — the grading signal is correct duplicate handling on both the outer fix-one loop and the inner two-pointer walk.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in JPMorgan loops.

  • Glassdoor (2026-Q1)Recurring JPMorgan SDE onsite problem after Two Sum on phone screens.
  • LeetCode (2026-Q1)Tagged JPMorgan on the LeetCode company tag page.
  • Reddit r/cscareerquestions (2025-12)JPMC senior SDE write-up: 'two-pointer with duplicate skipping — they care about clean dedup'.

Problem

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0. Notice that the solution set must not contain duplicate triplets.

Constraints

  • 3 <= nums.length <= 3000
  • -10^5 <= nums[i] <= 10^5

Examples

Example 1

Input
nums = [-1,0,1,2,-1,-4]
Output
[[-1,-1,2],[-1,0,1]]

Example 2

Input
nums = [0,1,1]
Output
[]

Example 3

Input
nums = [0,0,0]
Output
[[0,0,0]]

Approaches

1. Brute-force triple loop

Three nested loops; sort each candidate triplet and dedupe via a set.

Time
O(n^3)
Space
O(n) for the dedup set
function threeSumBrute(nums) {
  const result = new Set();
  for (let i = 0; i < nums.length; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      for (let k = j + 1; k < nums.length; k++) {
        if (nums[i] + nums[j] + nums[k] === 0) {
          const t = [nums[i], nums[j], nums[k]].sort((a, b) => a - b);
          result.add(t.join(','));
        }
      }
    }
  }
  return [...result].map((s) => s.split(',').map(Number));
}

Tradeoff: Trivially correct but TLEs at n=3000 (27 billion checks). Useful only to motivate the sort-then-two-pointer approach.

2. Sort + fix-one + two-pointer (optimal)

Sort. Fix nums[i] and run a two-pointer (l = i+1, r = n-1) on the remainder. Skip duplicate values on i, l, and r to avoid duplicate triplets.

Time
O(n^2)
Space
O(1) extra (ignoring output)
function threeSum(nums) {
  nums.sort((a, b) => a - b);
  const out = [];
  for (let i = 0; i < nums.length - 2; i++) {
    if (nums[i] > 0) break;
    if (i > 0 && nums[i] === nums[i - 1]) continue;
    let l = i + 1;
    let r = nums.length - 1;
    while (l < r) {
      const sum = nums[i] + nums[l] + nums[r];
      if (sum === 0) {
        out.push([nums[i], nums[l], nums[r]]);
        while (l < r && nums[l] === nums[l + 1]) l++;
        while (l < r && nums[r] === nums[r - 1]) r--;
        l++;
        r--;
      } else if (sum < 0) {
        l++;
      } else {
        r--;
      }
    }
  }
  return out;
}

Tradeoff: O(n^2) time and O(1) extra space beyond the output array — the canonical answer. The three duplicate-skip lines are what most candidates forget, producing duplicate triplets in the output.

JPMorgan-specific tips

JPMorgan interviewers grade the duplicate-handling logic more than the two-pointer dance. The three required skips are: (1) skip nums[i] when it equals the previous fixed value; (2) after a hit, advance l past consecutive duplicates; (3) after a hit, retreat r past consecutive duplicates. State all three before writing — that articulation reads as 'this is not your first time and you have thought about correctness'.

Common mistakes

  • Forgetting to sort first — the two-pointer pattern requires order.
  • Using a Set<string> to dedupe instead of skipping duplicates explicitly — produces correct output but is slower and harder to reason about.
  • Skipping duplicates on i only (not on l and r after a hit) — produces duplicate triplets.
  • Early-break on nums[i] > 0 is correct (no negative remainder can sum to zero), but candidates often forget it and waste cycles.

Follow-up questions

An interviewer at JPMorgan may pivot to one of these next:

  • 3Sum Closest (LC 16) — return the triplet sum closest to a given target.
  • 4Sum (LC 18) — extend with another outer loop; O(n^3).
  • kSum recursive framework — generalises 2Sum / 3Sum / 4Sum.
  • What if the input were a stream and you must answer 'is there a triplet summing to zero so far'?

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why sort first instead of using a hash map (a la 2Sum)?

You could fix one value and run 2Sum-with-hash on the remainder, also O(n^2), but the duplicate-skipping logic becomes harder. The sort + two-pointer formulation makes dedup falls out of the comparison structure — three skip-equal-while loops cover it cleanly.

What is the worst-case test that breaks beginner solutions?

[0, 0, 0, 0]. A correct solution returns exactly [[0,0,0]] once; beginners often return it four times (once per choice of which zero is the fixed element). The 'skip duplicates on i' guard is what fixes this.

Free learning resources

Curated free links for this problem.

Practice these live with InterviewChamp.AI

Drill 3Sum and other JPMorgan interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →