Two Sum Problem Classic Hash Solution in DSA Typescript - Time & Space Complexity
We want to understand how fast the classic hash-based solution for the Two Sum problem runs as the input grows.
Specifically, how does the number of steps change when the list of numbers gets bigger?
Analyze the time complexity of the following code snippet.
function twoSum(nums: number[], target: number): number[] {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement)!, i];
}
map.set(nums[i], i);
}
return [];
}
This code finds two numbers in the array that add up to the target using a hash map for quick lookups.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: One loop that goes through each number once.
- How many times: Exactly n times, where n is the length of the input array.
- Inside the loop, each hash map check and insert is done in constant time.
As the input size grows, the number of steps grows roughly the same way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks and inserts |
| 100 | About 100 checks and inserts |
| 1000 | About 1000 checks and inserts |
Pattern observation: The work grows linearly with input size; doubling input roughly doubles the work.
Time Complexity: O(n)
This means the time it takes grows in direct proportion to the number of elements in the input.
[X] Wrong: "Because there is a loop inside a loop, the time is O(n²)."
[OK] Correct: There is only one loop. The hash map operations inside the loop are fast and do not add extra loops, so the time stays linear.
Understanding this solution's time complexity shows you can use data structures smartly to speed up problems that might seem slow at first.
"What if the input array was sorted and we used two pointers instead of a hash map? How would the time complexity change?"
Practice
Solution
Step 1: Understand the role of hash map
The hash map stores each number as a key and its index as the value for quick lookup.Step 2: Explain why quick lookup is needed
Quick lookup helps to find if the complement (target - current number) exists without scanning the entire array again.Final Answer:
To store numbers and their indices for quick lookup -> Option CQuick Check:
Hash map stores number:index = A [OK]
- Thinking hash map sorts the array
- Trying to store sums instead of indices
- Using hash map to reverse elements
Solution
Step 1: Identify correct hash map initialization
In TypeScript,new Map<number, number>()creates a map with number keys and values.Step 2: Explain why other options are incorrect
{}is an object but lacks type safety;new Array()is an array, not a map;new Set()stores unique values, not key-value pairs.Final Answer:
const map = new Map<number, number>(); -> Option AQuick Check:
Use Map<number, number> for hash map [OK]
- Using Set instead of Map
- Using Array instead of Map
- Using plain object without type safety
[2, 7, 11, 15] and target 9?
function twoSum(nums: number[], target: number): number[] {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement)!, i];
}
map.set(nums[i], i);
}
return [];
}
console.log(twoSum([2, 7, 11, 15], 9));Solution
Step 1: Trace the loop and map updates
i=0: map={}, complement=9-2=7, map.has(7)? No, map.set(2,0).
i=1: complement=9-7=2, map.has(2)? Yes, index=0, return [0,1].Step 2: Confirm returned indices
Indices 0 and 1 correspond to numbers 2 and 7 which sum to 9.Final Answer:
[0, 1] -> Option DQuick Check:
Indices of 2 and 7 = [0, 1] [OK]
- Returning values instead of indices
- Not checking map before insertion
- Returning empty array incorrectly
function twoSum(nums: number[], target: number): number[] {
const map = new Map();
for (let i = 0; i <= nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement)!, i];
}
map.set(nums[i], i);
}
return [];
}Solution
Step 1: Analyze loop condition
The loop usesi <= nums.length, which causes out-of-bounds access at last iteration.Step 2: Correct loop condition
Change toi < nums.lengthto avoid accessing undefined element.Final Answer:
Loop condition should be < instead of <= -> Option BQuick Check:
Loop must stay within array bounds [OK]
- Off-by-one error in loop condition
- Swapping order of map.set and map.has
- Returning values instead of indices
[3, 3, 4, 5] and target 6, what will the Two Sum classic hash solution return?
function twoSum(nums: number[], target: number): number[] {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement)!, i];
}
map.set(nums[i], i);
}
return [];
}
console.log(twoSum([3, 3, 4, 5], 6));Solution
Step 1: Trace the loop and map updates with duplicates
i=0: map={}, complement=6-3=3, map.has(3)? No, map.set(3,0).
i=1: complement=6-3=3, map.has(3)? Yes, index=0, return [0,1].Step 2: Confirm correct pair with duplicates
Even with duplicates, first pair indices 0 and 1 sum to 6.Final Answer:
[0, 1] -> Option AQuick Check:
Duplicates handled, indices [0,1] sum to target [OK]
- Ignoring duplicates and returning wrong indices
- Returning empty array incorrectly
- Confusing values with indices
Ready to prove it?
Pass the test and this pattern moves unknown
