1. Two Sum
Problem Details
- π Link: https://leetcode.com/problems/two-sum/
- π Difficulty: Easy
- π’ Asked By: Amazon, Google, Meta, Apple
- π·οΈ Category: Arrays & Hashing
- π Similar Problems: LC 167 (Two Sum II), LC 15 (3Sum), LC 18 (4Sum), LC 560 (Subarray Sum Equals K)
π Problem Statement
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice. You can return the answer in any order.
Examples
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1]
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Explanation: nums[1] + nums[2] == 6, so return [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
Explanation: Two different indices with same value sum to target
Constraints
2 <= nums.length <= 10^4-10^9 <= nums[i] <= 10^9-10^9 <= target <= 10^9- Only one valid answer exists
π‘ Implication of constraints:
- β Array always has β₯ 2 elements (guaranteed pair exists)
- β Can return immediately upon finding solution (exactly one answer)
- β Large value range (-10βΉ to 10βΉ) β Cannot use array indexing, must use HashMap
- β Values can be negative, zero, or positive β Handle all cases
π« Approach 1 β Brute Force
Thought Process
π The Most Obvious Way:
- Try all possible pairs of numbers in the array
- For each element, check it against every other element
- Start with first element β check against all others
- Move to second element β check against all remaining
- Continue until pair found that sums to target
- Direct translation of problem into code (no clever optimization)
Algorithm / Pseudocode
Step 1: Outer loop with index i from 0 to length-2
(Stop at length-2 because need at least one element after current)
Step 2: For each i, inner loop with index j from i+1 to length-1
(Start from i+1 to avoid using same element twice)
Step 3: For each pair (i, j):
- Calculate sum: nums[i] + nums[j]
- If sum equals target β return [i, j] immediately
Step 4: If all pairs checked with no match:
- Return empty array (never happens due to constraints)
Code
class Solution {
public int[] twoSum(int[] nums, int target) {
// Outer loop: consider each element as first number in pair
// Stop at length-1 because we need at least one more element
for (int i = 0; i < nums.length - 1; i++) {
// Inner loop: check all elements after position i
// Starting from i+1 prevents using same element twice
for (int j = i + 1; j < nums.length; j++) {
// Check if current pair sums to target
if (nums[i] + nums[j] == target) {
// Found our answer! Return indices immediately
return new int[] {i, j};
}
}
}
// Never executes (problem guarantees exactly one solution)
// Required by Java to ensure all paths return a value
return new int[] {};
}
}
Dry Run
π Walking Through Example: nums = [3, 2, 4], target = 6
Initial Setup:
βββββββββββββββββββββββββββββββββββββββββββββββ
Array: [3, 2, 4]
Index: 0 1 2
Target: 6
βββββββββββββββββββββββββββββββββββββββββββββββ
Execution Trace Table:
ββββββββ¬ββββ¬ββββ¬ββββββββββ¬ββββββββββ¬ββββββ¬βββββββββ¬βββββββββββββββββββ
β Step β i β j β nums[i] β nums[j] β Sum β Match? β Action β
ββββββββΌββββΌββββΌββββββββββΌββββββββββΌββββββΌβββββββββΌβββββββββββββββββββ€
β 1 β 0 β 1 β 3 β 2 β 5 β β β Continue β
β 2 β 0 β 2 β 3 β 4 β 7 β β β Continue β
β 3 β 1 β 2 β 2 β 4 β 6 β β
β Return [1,2] β
ββββββββ΄ββββ΄ββββ΄ββββββββββ΄ββββββββββ΄ββββββ΄βββββββββ΄βββββββββββββββββββ
Detailed Step-by-Step:
βββββββββββββββββββββββββββββββββββββββββββββββ
Step 1: i=0, j=1
Checking pair at indices [0, 1]
Values: nums[0]=3, nums[1]=2
Sum: 3 + 2 = 5
Does 5 == 6? β No
β Continue to next pair
Step 2: i=0, j=2
Checking pair at indices [0, 2]
Values: nums[0]=3, nums[2]=4
Sum: 3 + 4 = 7
Does 7 == 6? β No
β Outer loop increments i to 1
Step 3: i=1, j=2
Checking pair at indices [1, 2]
Values: nums[1]=2, nums[2]=4
Sum: 2 + 4 = 6
Does 6 == 6? β
Yes!
β Return [1, 2] immediately
βββββββββββββββββββββββββββββββββββββββββββββββ
Result: [1, 2] after checking 3 pairs
βββββββββββββββββββββββββββββββββββββββββββββββ
Time & Space Complexity
β° Time Complexity: O(nΒ²)
- Outer loop runs n-1 iterations
- Inner loop runs progressively fewer times: (n-1) + (n-2) + ... + 1
- Total comparisons: (n-1) Γ n / 2 β nΒ²/2
- Simplifies to O(nΒ²) in Big-O notation
πΎ Space Complexity: O(1)
- Only constant extra space used
- Two loop variables i, j (fixed size)
- Result array not counted (required output)
- No data structures that grow with input
β Approach 3 β Optimal (Final)
Thought Process (How did you arrive here)
π― The Breakthrough Insight:
Brute Force Problem: Checking every pair repeatedly is wasteful
β
Key Question: For each number, what are we looking for?
β We know EXACTLY what we need: the complement!
β
Insight: Instead of searching forward from each position,
REMEMBER what we've already seen
β
Solution: Use HashMap for instant O(1) lookups
"Have I seen this complement before?"
β
Trade-off: Sacrifice O(n) space to gain O(n) time
π Why Check BEFORE Adding:
- If we add first, then check β Need two passes
- If we check first, then add β Single pass! β¨
- Bonus: Automatically prevents using same element twice
Algorithm / Pseudocode
Step 1: Create empty HashMap to store (number β index) mapping
Step 2: Iterate through array once (index i from 0 to length-1):
a. Calculate complement = target - nums[i]
(This is the value we need to find)
b. Check if complement exists in HashMap:
IF FOUND:
β
We found our pair!
β
Return [map.get(complement), i]
β
Complement's index first (was seen earlier)
IF NOT FOUND:
βοΈ Haven't seen complement yet
βοΈ Store current element: map.put(nums[i], i)
βοΈ Continue to next iteration
Step 3: Return empty array (never reached, solution guaranteed)
Code
import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] twoSum(int[] nums, int target) {
// HashMap stores each number and its index as we traverse
// Key: number value | Value: its index in array
Map<Integer, Integer> numToIndex = new HashMap<>();
// Single pass through array
for (int i = 0; i < nums.length; i++) {
// Calculate what complement we need
// If nums[i] + complement = target
// Then complement = target - nums[i]
int complement = target - nums[i];
// Check if we've already seen this complement
if (numToIndex.containsKey(complement)) {
// β
Found our pair! Return the two indices
// Complement was seen earlier, so its index comes first
return new int[] {numToIndex.get(complement), i};
}
// βοΈ Haven't seen complement yet
// Store current number and index for future reference
numToIndex.put(nums[i], i);
}
// Never reached (guaranteed exactly one solution exists)
return new int[] {};
}
}
Dry Run
π Step-by-Step Execution: nums = [2, 7, 11, 15], target = 9
Initial Setup:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Array: [2, 7, 11, 15]
Index: 0 1 2 3
Target: 9
HashMap: {} (empty)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Execution Table:
ββββββββ¬ββββ¬ββββββββββ¬ββββββββββββββββββ¬βββββββββββββ¬βββββββββββββββββ¬βββββββββ¬βββββββββββββββ
β Step β i β nums[i] β Complement β HashMap β Complement β Action β HashMap β
β β β β (9-nums[i]) β Before β Found? β β After β
ββββββββΌββββΌββββββββββΌββββββββββββββββββΌβββββββββββββΌβββββββββββββββββΌβββββββββΌβββββββββββββββ€
β 1 β 0 β 2 β 7 β {} β β No βAdd 2β0 β {2β0} β
β 2 β 1 β 7 β 2 β {2β0} β β
Yes (at 0) βReturn β {2β0} β
β β β β β β β [0,1] β β
ββββββββ΄ββββ΄ββββββββββ΄ββββββββββββββββββ΄βββββββββββββ΄βββββββββββββββββ΄βββββββββ΄βββββββββββββββ
Detailed Trace:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Iteration 1: i=0
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Current element: nums[0] = 2 β
β Calculate complement: 9 - 2 = 7 β
β β
β Check HashMap for 7: β
β HashMap: {} β
β Contains 7? β NO β
β β
β Action: Add current element to map β
β map.put(2, 0) β
β β
β HashMap state: {2 β 0} β
β Continue to next iteration... β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Iteration 2: i=1
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Current element: nums[1] = 7 β
β Calculate complement: 9 - 7 = 2 β
β β
β Check HashMap for 2: β
β HashMap: {2 β 0} β
β Contains 2? β
YES! β
β β
β Action: Found our pair! β
β Complement 2 is at index 0 (from HashMap) β
β Current element 7 is at index 1 β
β Return [0, 1] immediately β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π― Final Result: [0, 1]
β‘ Efficiency: Found answer in just 2 iterations (out of 4 possible)
β¨ Never checked pairs: (2,11), (2,15), (7,11), (7,15)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Insights from This Run:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
HashMap provided instant O(1) lookup for complement
β
Early exit as soon as solution found
β
Single pass through array (optimal)
β
No redundant pair checking
Time & Space Complexity
β° Time Complexity: O(n)
- Single pass through array: n iterations maximum
- Each iteration performs:
- HashMap lookup (containsKey): O(1) average
- HashMap insertion (put): O(1) average
- Total: n Γ O(1) = O(n) linear time
πΎ Space Complexity: O(n)
- HashMap can store up to n elements in worst case
- Worst case: Answer is last two elements
- Must store all previous n-2 elements before finding solution
- Example: [1,2,3,4,5], target=9 β stores 1,2,3,4 before finding 4+5
- Trade-off: Used O(n) space to improve time from O(nΒ²) to O(n)
Space-Time Trade-off Visualization:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Brute Force: Time O(nΒ²) Space O(1) β οΈ Slow but no extra space
Optimal: Time O(n) Space O(n) β¨ Fast with reasonable space
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Edge Cases & Testing
Edge Cases
1. Minimum Size Array (n=2):
Input: [1, 2], target = 3
Output: [0, 1]
π§ͺ Tests: Base case with smallest valid input
2. Negative Numbers:
Input: [-3, 4, 3, 90], target = 0
Output: [0, 2] (because -3 + 3 = 0)
π§ͺ Tests: Handling of negative values
3. Duplicate Values (Same value, different indices):
Input: [3, 3], target = 6
Output: [0, 1]
π§ͺ Tests: Can use same value at different positions
π§ͺ Tests: HashMap overwrites correctly
4. Zero in Array:
Input: [0, 4, 3, 0], target = 0
Output: [0, 3] (because 0 + 0 = 0)
π§ͺ Tests: Zero handling
5. Large Numbers Near Integer Limits:
Input: [1000000000, 999999999, 1], target = 1999999999
π§ͺ Tests: Boundary of int range
π§ͺ Tests: No integer overflow in calculations
6. Solution at Beginning:
Input: [2, 7, 11, 15], target = 9
Output: [0, 1]
π§ͺ Tests: Early exit optimization
7. Solution at End:
Input: [11, 15, 2, 7], target = 9
Output: [2, 3]
π§ͺ Tests: Full traversal scenario
8. Negative Target:
Input: [-1, -2, -3, -4], target = -6
Output: [1, 3] (because -2 + -4 = -6)
π§ͺ Tests: Negative target handling
Test Suite
β Basic Tests:
Test 1: nums = [2,7,11,15], target = 9
Expected: [0,1]
Test 2: nums = [3,2,4], target = 6
Expected: [1,2]
Test 3: nums = [3,3], target = 6
Expected: [0,1]
π Edge Tests:
Test 4: Minimum size
nums = [1,2], target = 3
Expected: [0,1]
Test 5: Negative numbers
nums = [-1,-2,-3,-4,-5], target = -8
Expected: [2,4] (because -3 + -5 = -8)
Test 6: With zeros
nums = [0,4,3,0], target = 0
Expected: [0,3]
Test 7: Negative target
nums = [1,-1,2,-2], target = -3
Expected: [1,3] (because -1 + -2 = -3)
πͺ Stress Tests:
Test 8: Large array (performance test)
nums = [1,2,3,...,9999,10000], target = 19999
Expected: [9998,9999]
Validates: O(n) time efficiency
Test 9: Large values near limits
nums = [1000000000,-999999999,1], target = 1
Expected: [1,2]
Validates: No integer overflow
Test 10: Solution at different positions
nums = [5,75,25], target = 100
Expected: [1,2]
Validates: Works regardless of solution position
π Weekly Quick Revision (Memory Boosters)
π― The Essence in 7 Lines
Two Sum asks for indices of two numbers that sum to target
Brute Force: Check all pairs in O(nΒ²) time with nested loops
β
Optimal: Use HashMap to store seen numbers for O(1) complement lookup
β
For each number, calculate complement (target - current)
β
Check if complement exists in map BEFORE adding current number
β
Single pass O(n) time, O(n) space solution
π‘ Mental Trigger
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WHEN YOU SEE: β
β "Find two elements that sum/match to target" β
β β
β IMMEDIATELY THINK: β
β β¨ HashMap for complement lookup β
β β¨ Check before storing β
β β¨ Single pass solution β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Quick Algorithm Recall
// The 5-line pattern you need to remember:
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) return new int[] {map.get(complement), i};
map.put(nums[i], i);
}
π Core Pattern Recognition
Problem Type: Two Sum β HashMap Complement Pattern
When to Apply:
β Finding pairs with specific relationship
β Can rearrange equation to isolate search target
β Need to optimize from O(nΒ²) to O(n)
β Order doesn't matter for correctness
Related Problems:
β Two Sum II (sorted array β use two pointers instead)
β 3Sum (extends to three elements)
β 4Sum (extends to four elements)
β Subarray Sum Equals K (uses similar complement concept)