2Brute2Best
🔥0

Two Sum

Easy·LeetCode #1Basic Anchor
LeetCode
30-Second Mental ModelHash Map — Complement Lookup (value → index)
Complexity:O(N²)→O(N)
Key Insight

Walk the array once. Standing on nums[i], its partner must be target − nums[i]. Keep a map value → index of the elements already passed. If the partner is in the map, we are done. If not, store nums[i] and move on.

Core Validity Invariant

nums[i] has a partner exactly when target − nums[i] is already in seen. Because seen only holds elements before i, the partner is always a different position.

01

Problem

You are given an integer array nums and an integer target.

Find two different positions i and j such that nums[i] + nums[j] == target, and return those two indices. Exactly one such pair exists. You may not use the same element twice, but two different elements may hold the same value. The indices can be returned in any order.

Input

An integer array nums and an integer target.

Output

A list of two indices [i, j] with i ≠ j and nums[i] + nums[j] == target.

Example 1
Input: nums = [2, 7, 11, 15], target = 9
Output: [0, 1]

nums[0] + nums[1] = 2 + 7 = 9.

Example 2
Input: nums = [3, 2, 4], target = 6
Output: [1, 2]

2 + 4 = 6. Note that 3 + 3 is not allowed: there is only one 3, and it can't be used twice.

Example 3
Input: nums = [3, 3], target = 6
Output: [0, 1]

Two different elements with the same value are fine.

Constraints
  • • 2 ≤ nums.length ≤ 10^4
  • • −10^9 ≤ nums[i] ≤ 10^9
  • • −10^9 ≤ target ≤ 10^9
  • • Exactly one valid answer exists.
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    If I stand on nums[i], which exact value would its partner need to have?

  2. 2.

    Do I need to search the whole array for that partner, or only the part I have already walked past?

  3. 3.

    The answer asks for indices. What happens to the indices if I sort the array?

  4. 4.

    How do I make sure an element is not used as its own partner, while [3, 3] with target 6 still works?

  5. 5.

    Can target − nums[i] overflow an int?

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceCheck all pairs (i, j) with i < jO(N²)O(1)
BetterSort copies that remember their index, then squeeze from both endsO(N log N)O(N)
OptimalFor each x, look up target − x in a map of earlier values; then store xO(N)O(N)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “two numbers that add up to target”Once you pick one number, the other is fixed: `target − x`. That is a complement lookup.
  • “return their indices”You must keep original positions. Store `value → index` in the map, and don't sort plain values.
  • “array is not sorted”Two pointers need sorted order. Without it, use a hash map.
  • “can't use the same element twice”Look up before inserting, so the map only holds earlier elements.
Pair with an exact sum+unsorted array+need indices→Hash Map — Complement Lookup (value → index)

This is the anchor of the sub-pattern: for each element, compute the one partner it needs and ask the map if that partner was seen before. The next questions keep this shape but change what is stored. Contains Duplicate II stores the last index of each value and the "partner" is the same value nearby. Max Number of K-Sum Pairs stores counts, because each element can be used only once. If the array were already sorted (Two Sum II), two pointers would do it with O(1) space.

10

Don't make this mistake

Using two pointers on the unsorted array
✗ int l = 0, r = n - 1; while (l < r) { if (nums[l] + nums[r] == target) return {l, r}; if (nums[l] + nums[r] < target) l++; else r--; }
✓ // unsorted → hash map of earlier values if (seen.count(target - nums[i])) return {seen[target - nums[i]], i}; seen[nums[i]] = i;

This is a pattern-confusion trap: the two-pointer move is Two Sum II, where the array is sorted. "Sum too small → move left" is only safe when everything to the right is bigger. On [3, 2, 4], target 6, it checks 3+4=7, moves r, checks 3+2=5, moves l, and stops — it never finds 2+4.

Sorting the values and losing the indices
✗ sort(nums.begin(), nums.end()); // ... two pointers ... return {l, r}; // positions in the SORTED array
✓ vector<pair<int,int>> a; // (value, original index) // sort a, two pointers, then return {a[l].second, a[r].second};

Sorting moves elements, so l and r are positions in the sorted copy, not the original array. On [3, 2, 4], target 6, it returns [0, 2], but the right answer is [1, 2]. Sort (value, index) pairs, or use the map.

Inserting before looking up
✗ seen[nums[i]] = i; if (seen.count(target - nums[i])) return {seen[target - nums[i]], i};
✓ if (seen.count(target - nums[i])) return {seen[target - nums[i]], i}; seen[nums[i]] = i;

When nums[i] is exactly half of target, the lookup finds nums[i] itself. On [3, 2, 4], target 6, it returns [0, 0] — the same element used twice.

Putting every value in the map first
✗ for (int i = 0; i < n; i++) seen[nums[i]] = i; for (int i = 0; i < n; i++) if (seen.count(target - nums[i])) return {i, seen[target - nums[i]]};
✓ for (int i = 0; i < n; i++) if (seen.count(target - nums[i]) && seen[target - nums[i]] != i) return {i, seen[target - nums[i]]};

The two-pass version can work, but only with the extra != i check. Without it, [3, 2, 4] returns [0, 0]. The one-pass "look up, then insert" order gives you that check for free.

Overflow in target − x
✗ int need = target - nums[i];
✓ long long need = (long long)target - nums[i];

With target = −10^9 and nums[i] = 10^9, the result is −2·10^9, which is outside the int range. On LeetCode it is usually fine, but it is undefined behaviour in C++.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Arrays & Hashing translate into production architectures and low-level memory mechanics.