LeetCode · Problem 1

LeetCode 1 Two Sum: From Brute Force to HashMap, Plus Every Variant

The three solutions and when each is right, a one-pass HashMap you can defend line by line, the sorted and counting variants, the jump to 3Sum, and the follow-up questions that turn the easiest problem on LeetCode into a real interview.

✍️ Pranjal Jain, Ex-Microsoft · IIT Kanpur 📅 10 October 2026 ⏱ 15 min read
Two matching puzzle pieces finding each other among many, representing the Two Sum problem
TL;DR
  • Best answer: one pass with a hash map from value to index. For each x, look up target - x; if found, return; else store x. O(n) time, O(n) space.
  • Look up before you insert so an element never pairs with itself, and [3, 3] works.
  • Sorted input (Two Sum II): two pointers, O(n) time, O(1) space.
  • 3Sum = sort, fix one element, two-pointer Two Sum on the rest, skip duplicates. O(n²).
  • Interviewers care about the follow-ups: all pairs, duplicates, streams, memory limits, data that does not fit in RAM.

Two Sum is LeetCode problem number 1 and probably the most solved coding problem in the world. That is exactly why answering it well is harder than it looks: the interviewer has heard the HashMap answer hundreds of times and is waiting to see whether you can justify it, handle its edge cases, and adapt it when they change the constraints. This page covers the three approaches with tested C++, Java and Python, then every variant and follow-up worth preparing.

The Problem and the Questions to Ask First

Given an array of integers nums and an integer target, return the indices of the two numbers that add up to target. LeetCode guarantees exactly one solution and says you may not use the same element twice; the answer can be returned in any order.

Example: nums = [2, 7, 11, 15], target = 9 returns [0, 1] because 2 + 7 = 9.

In an interview the guarantees are not always stated. Ask, because each answer changes the solution:

QuestionIf the answer is...Then
Indices or values?ValuesSorting + two pointers becomes attractive
Is the array sorted?YesTwo pointers, O(1) space
Exactly one answer? None possible?Maybe noneDefine the return value: empty array, [-1, -1], or exception
All pairs or one?AllOutput can be O(n²); clarify duplicates and uniqueness
Duplicates? Negatives?YesThe hash map handles both; check overflow on the sum
Can I modify the input?NoSorting in place is off the table without a copy

Asking these takes thirty seconds and is itself part of the signal, as described in the step-by-step method for approaching DSA problems.

Approach 1: Brute Force, O(n²)

Check every pair (i, j) with i < j.

Python
def two_sum_brute(nums, target):
    n = len(nums)
    for i in range(n):
        for j in range(i + 1, n):
            if nums[i] + nums[j] == target:
                return [i, j]
    return []

O(n²) time, O(1) space. With LeetCode's limit of 104 elements it is about 5 × 107 comparisons, which actually passes, but interviewers expect you to state it and move on. The useful observation is why it is slow: for each nums[i], the inner loop is searching for one specific value, target - nums[i]. Searching for a specific value is what hash tables are for.

Approach 2: One-Pass HashMap, O(n)

Keep a map from value to index of everything seen so far. For each element, the partner it needs is target - x. If that partner was already seen, you are done; otherwise remember x for future elements.

C++
vector<int> twoSum(const vector<int>& nums, int target) {
    unordered_map<int, int> seen;              // value -> index
    for (int i = 0; i < (int)nums.size(); i++) {
        auto it = seen.find(target - nums[i]);
        if (it != seen.end()) return {it->second, i};
        seen[nums[i]] = i;
    }
    return {};
}
Java
public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> seen = new HashMap<>();   // value -> index
    for (int i = 0; i < nums.length; i++) {
        Integer j = seen.get(target - nums[i]);
        if (j != null) return new int[]{j, i};
        seen.put(nums[i], i);
    }
    return new int[0];
}
Python
def two_sum(nums, target):
    seen = {}                      # value -> index
    for i, x in enumerate(nums):
        need = target - x
        if need in seen:
            return [seen[need], i]
        seen[x] = i
    return []

Why one pass is enough: if the answer is the pair (i, j) with i < j, then when the loop reaches j, nums[i] is already in the map. So the pair is always found at its second element. The two-pass variant (fill the map, then scan) also works but needs an explicit seen[need] != i check to avoid self-pairing.

In Java, note Integer j = seen.get(...) with a null check rather than containsKey followed by get: one lookup instead of two, and no unboxing of a null. The Java Collections cheat sheet covers why comparing Integer values with == would be a bug here.

Dry Run and Edge Cases

nums = [3, 2, 4], target = 6:

ixneed = 6 - xneed in map?map after
033No (map empty, so 3 is not paired with itself){3: 0}
124No{3: 0, 2: 1}
242Yes, index 1return [1, 2]

Note the first row: a naive solution that pre-fills the map would return [0, 0] for this input. Edge cases to say aloud:

  • [3, 3], target 6 returns [0, 1]: the first 3 is stored before the second looks it up.
  • Negatives and zero: [-3, 4, 3, 90], target 0 returns [0, 2]; no special handling needed.
  • Overflow: target - x can overflow a 32-bit int when both are near the limits. Under LeetCode's constraints (values and target within ±109) the result stays within ±2 × 109, just inside INT_MAX ≈ 2.147 × 109, so int is safe there. Say that you checked; with unknown bounds, compute in 64-bit.
  • No answer: returns an empty array; agree on the convention.

Approach 3: Sorting + Two Pointers

If the array were sorted, you could put one pointer at each end. If the sum is too small, move the left pointer right (the only way to increase it); too big, move the right pointer left. Each step discards one element for good, so the scan is O(n).

For LeetCode 1 you need original indices, so sort the indices by value:

Python
def two_sum_sort_indices(nums, target):
    order = sorted(range(len(nums)), key=lambda i: nums[i])
    lo, hi = 0, len(order) - 1
    while lo < hi:
        s = nums[order[lo]] + nums[order[hi]]
        if s == target:
            return sorted([order[lo], order[hi]])
        if s < target:
            lo += 1
        else:
            hi -= 1
    return []

O(n log n) time and O(n) space for the index array, so it is strictly worse than hashing for this exact problem. Why learn it? Because it is the right tool when (a) the input is already sorted, (b) you need all unique pairs by value, (c) you are building up to 3Sum, or (d) memory is tight and you may sort in place.

Why two pointers never skips the answer

Suppose the answer is values at sorted positions (p, q). While lo < p and hi > q both still hold, the pointers can only move inward. If lo reaches p first, then every sum a[p] + a[hi] with hi > q is at least a[p] + a[q] = target, so if it is strictly greater, hi moves left until it hits q. Symmetric for hi reaching q first. Interviewers ask this proof surprisingly often; the two pointers guide uses the same argument for Container With Most Water.

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

The array is sorted, indices are 1-based, and you must use O(1) extra space. Exactly the two-pointer scan:

Java
public int[] twoSumSorted(int[] numbers, int target) {
    int lo = 0, hi = numbers.length - 1;
    while (lo < hi) {
        int s = numbers[lo] + numbers[hi];
        if (s == target) return new int[]{lo + 1, hi + 1};   // 1-indexed
        if (s < target) lo++;
        else hi--;
    }
    return new int[0];
}

Using a hash map here works but ignores the sortedness and uses O(n) memory, which interviewers will point out. Binary searching the partner for each element is O(n log n), better than brute force but worse than two pointers.

ApproachTimeExtra spaceKeeps indicesBest when
Brute forceO(n²)O(1)Yesn is tiny
HashMap one passO(n)O(n)YesUnsorted input, indices needed (LC 1)
Sort + two pointersO(n log n)O(1) to O(n)Only with index sortValues needed, unique pairs, 3Sum
Two pointers on sortedO(n)O(1)YesAlready sorted (LC 167)
Binary search per elementO(n log n)O(1)YesSorted, but rarely the best

Counting All Pairs and Unique Pairs

Count all index pairs with sum = target

Store counts instead of a single index. Each new element pairs with every earlier occurrence of its complement.

Python
from collections import Counter

def count_pairs(nums, target):
    seen = Counter()
    count = 0
    for x in nums:
        count += seen[target - x]
        seen[x] += 1
    return count
# [1, 1, 1, 1], target 2 -> 6 (every pair of the four 1s)
# [1, 5, 7, -1, 5], target 6 -> 3: (1,5), (7,-1), (1,5)

This is the same "count complements seen so far" idea that solves Subarray Sum Equals K with prefix sums and Count Number of Nice Subarrays; see hashing interview problems.

All unique value pairs

Sort, two pointers, and skip equal neighbours after each match:

Python
def unique_pairs(nums, target):
    nums = sorted(nums)
    lo, hi = 0, len(nums) - 1
    out = []
    while lo < hi:
        s = nums[lo] + nums[hi]
        if s < target:
            lo += 1
        elif s > target:
            hi -= 1
        else:
            out.append((nums[lo], nums[hi]))
            lo += 1
            hi -= 1
            while lo < hi and nums[lo] == nums[lo - 1]:
                lo += 1
            while lo < hi and nums[hi] == nums[hi + 1]:
                hi -= 1
    return out
# [1, 1, 2, 45, 46, 46], target 47 -> [(1, 46), (2, 45)]

From Two Sum to 3Sum (LeetCode 15)

Find all unique triplets that sum to 0. Fix the first element nums[i]; you now need a Two Sum with target -nums[i] on the elements to its right. Sorting first gives you both the two-pointer inner loop and an easy way to skip duplicates.

C++
vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> res;
    int n = nums.size();
    for (int i = 0; i + 2 < n; i++) {
        if (nums[i] > 0) break;                            // smallest is positive: done
        if (i > 0 && nums[i] == nums[i - 1]) continue;      // skip duplicate anchors
        int lo = i + 1, hi = n - 1;
        while (lo < hi) {
            int s = nums[i] + nums[lo] + nums[hi];
            if (s < 0) lo++;
            else if (s > 0) hi--;
            else {
                res.push_back({nums[i], nums[lo], nums[hi]});
                lo++; hi--;
                while (lo < hi && nums[lo] == nums[lo - 1]) lo++;   // skip duplicate seconds
            }
        }
    }
    return res;
}
Python
def three_sum(nums):
    nums.sort()
    res = []
    n = len(nums)
    for i in range(n - 2):
        if nums[i] > 0:
            break
        if i > 0 and nums[i] == nums[i - 1]:
            continue
        lo, hi = i + 1, n - 1
        while lo < hi:
            s = nums[i] + nums[lo] + nums[hi]
            if s < 0:
                lo += 1
            elif s > 0:
                hi -= 1
            else:
                res.append([nums[i], nums[lo], nums[hi]])
                lo += 1
                hi -= 1
                while lo < hi and nums[lo] == nums[lo - 1]:
                    lo += 1
    return res

For [-1, 0, 1, 2, -1, -4] it returns [[-1, -1, 2], [-1, 0, 1]]; for [0, 0, 0, 0], [[0, 0, 0]]. Both versions were checked against a brute-force set of triplets on thousands of random arrays. Time O(n²), extra space O(1) beyond the output and sort.

Why not a hash map inside 3Sum? It works in O(n²) too, but deduplicating triplets then needs a set of sorted tuples, which is messier and slower in practice. 4Sum (LC 18) adds one more fixed loop for O(n³); the general kSum recurses down to a two-pointer Two Sum, with O(nk-1) time. Related: 3Sum Closest (LC 16) uses the same scan while tracking the closest sum.

Other Two Sum Variants Worth Knowing

Two Sum III: Data Structure Design (LC 170)

Support add(number) and find(value) (does any pair sum to value?). Store counts in a hash map; add is O(1) and find scans distinct keys in O(n), being careful that a pair of equal numbers needs a count of at least 2.

Python
from collections import Counter

class TwoSum:
    def __init__(self):
        self.count = Counter()

    def add(self, number):
        self.count[number] += 1

    def find(self, value):
        for x, c in self.count.items():
            y = value - x
            if y != x and y in self.count:
                return True
            if y == x and c > 1:
                return True
        return False

The interesting discussion is the trade-off: if find is called far more often than add, precompute all pair sums into a set on each add (O(n) add, O(1) find). Saying "it depends on the read/write ratio" is exactly the kind of judgment interviewers look for.

Two Sum IV: Input Is a BST (LC 653)

Either traverse with a hash set (O(n) time and space), or do an inorder traversal to get a sorted list and use two pointers, or, for O(h) space, run two BST iterators (one ascending, one descending) as the two pointers. The iterator version is a strong answer for senior candidates.

Closest pair, less than K, and difference

  • Pair sum closest to target: sort + two pointers, track the best absolute difference.
  • Two Sum Less Than K (LC 1099): sort + two pointers, record sums below K.
  • Pair with difference k: hash set lookup of x + k and x - k, or sort and move two pointers in the same direction (K-diff Pairs, LC 532).
  • Count pairs with sum ≤ target: sort, two pointers; when a[lo] + a[hi] <= target, all pairs (lo, lo+1..hi) qualify, so add hi - lo and move lo.

Follow-Up Questions Interviewers Actually Ask

Follow-up

"Do it in O(1) extra space."

If modifying the input is allowed: sort in place and two pointers, O(n log n) time. You lose indices unless you can afford to store them. Without modification and without extra space, you are back to O(n²).

Follow-up

"Numbers arrive as a stream."

Keep the hash map of seen values and check each arrival's complement in O(1). If the stream is unbounded, discuss memory: a sliding time window with eviction, or approximate structures.

Follow-up

"The array has 10 billion numbers."

Doesn't fit in RAM. Hash-partition by value into files so that x and target - x land in paired partitions, then solve each partition pair in memory; or external sort plus a two-pointer merge across files.

Follow-up

"What is the worst case of your HashMap?"

O(n) per operation under adversarial collisions, so O(n²) total. Java 8+ converts long bucket chains into balanced trees for Comparable keys, bounding lookups to O(log n). Sorting gives a guaranteed O(n log n).

Other follow-ups you should have a one-line answer for:

  • "Return all pairs": output can be Θ(n²) (all equal values), so no algorithm beats that bound; clarify unique values vs index pairs.
  • "Floating-point numbers": exact-match hashing fails with rounding; sort and use two pointers with a tolerance.
  • "Multiple queries with different targets": sort once (O(n log n)), then each query is an O(n) two-pointer scan, or O(n) with a hash set per query.
  • "Distributed across machines": same hash-partitioning idea as the 10-billion case, one partition pair per worker.

Common Two Sum Mistakes

  1. Inserting before looking up, which lets an element pair with itself ([3, 2, 4], target 6 returns [0, 0]).
  2. Sorting the array in place and returning indices of the sorted array.
  3. Storing the map as index to value instead of value to index; then lookups by value are O(n).
  4. Two lookups per element (containsKey then get); fine for correctness, but say why you used a single get/find.
  5. Forgetting 1-based indices in Two Sum II.
  6. 3Sum duplicates: skipping duplicates at the wrong time (before recording the first match) loses valid triplets like [-1, -1, 2].
  7. Not stating complexity for both time and space, and not explaining why one pass suffices.
✅
A model 60-second answer"Brute force checks all pairs in O(n²). The inner loop is really searching for target minus x, so I'll keep a hash map from value to index of elements seen so far. For each element I check the complement first, then insert, so I never pair an element with itself and duplicates like [3, 3] work. That's O(n) time and O(n) space. If the input were sorted I'd use two pointers instead for O(1) space." Then code it, dry-run [3, 2, 4], and invite the follow-up.

Two Sum is also the first problem on every major list compared in Blind 75 vs NeetCode 150 vs Striver. Next in the two-pointer family, try Container With Most Water.

Frequently Asked Questions

What is the best solution for LeetCode Two Sum?▾
A one-pass hash map. For each element x at index i, check whether target - x has already been stored; if yes, return the stored index and i, otherwise store x with its index. It runs in O(n) time and O(n) space, and checking before inserting guarantees you never pair an element with itself.
Why not sort and use two pointers for Two Sum?▾
Sorting moves elements, so you lose the original indices that LeetCode 1 asks for unless you sort index pairs, and it costs O(n log n). Two pointers is the right choice when the array is already sorted (Two Sum II), when you must return values rather than indices, or when O(1) extra space matters and modifying the input is allowed.
How does Two Sum handle duplicate numbers like [3, 3] with target 6?▾
The one-pass hash map handles it naturally. At index 0 the map is empty, so 3 is stored. At index 1 the complement 3 is found at index 0, giving [0, 1]. Because you look up before inserting, an element is never matched with itself, and a later duplicate overwriting an earlier index does not matter once a pair is found.
What is the time complexity of Two Sum with a HashMap?▾
O(n) average time, since each of the n elements does one hash lookup and one insert in O(1) on average, and O(n) extra space for the map. In the worst case of heavy hash collisions lookups degrade, which is why some interviewers ask about the worst case and how Java mitigates it with tree bins.
How is Two Sum related to 3Sum?▾
3Sum fixes one element and solves Two Sum on the rest for the target minus that element. After sorting, each inner Two Sum is a two-pointer scan, giving O(n^2) total, and sorting also makes it easy to skip duplicate triplets. kSum generalises this recursively down to a two-pointer Two Sum.
Is Two Sum asked in real interviews?▾
The exact problem appears mostly as a warm-up, in phone screens, campus rounds and online assessments. More often interviewers use a variant: sorted input, counting all pairs, a data stream, a BST, closest sum, or 3Sum, and they probe trade-offs between hashing and sorting. Knowing the variants is what turns it from a giveaway into a scoring opportunity.

Turn Easy Problems Into Strong Signals

Prepflix mock interviews push every problem into its follow-ups, so you practise defending trade-offs like hashing versus sorting the way product-company interviewers expect.

Explore the Prepflix Course →
Pranjal Jain
Pranjal Jain

Ex-Microsoft SDE · IIT Kanpur · Founder of Prepflix. Helps engineers crack startup and product company interviews across India.