Two Sum Problem Classic Hash Solution in DSA C++ - Time & Space Complexity
We want to understand how fast the classic hash-based solution for the Two Sum problem runs.
Specifically, how the time to find two numbers that add up to a target grows as the input list gets bigger.
Analyze the time complexity of the following code snippet.
#include <unordered_map>
#include <vector>
std::vector<int> twoSum(const std::vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for (int i = 0; i < (int)nums.size(); ++i) {
int complement = target - nums[i];
if (map.find(complement) != map.end()) {
return {map[complement], i};
}
map[nums[i]] = i;
}
return {};
}
This code finds two numbers in the list that add up to the target using a hash map for quick lookups.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single loop over the input array.
- How many times: Exactly once for each element in the array.
- Inside the loop: A constant-time hash map lookup and insertion.
As the input size grows, the number of loop iterations grows linearly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 lookups and insertions |
| 100 | About 100 lookups and insertions |
| 1000 | About 1000 lookups and insertions |
Pattern observation: The operations increase directly with input size, doubling input roughly doubles work.
Time Complexity: O(n)
This means the time to find the two numbers grows in a straight line with the number of elements.
[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 lookups are fast and do not add extra loops.
Understanding this solution's time complexity shows you can use data structures smartly to speed up searches.
This skill is valuable for solving many problems efficiently in interviews and real projects.
"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 access.Step 2: Explain why quick lookup is needed
Quick lookup helps find if the complement (target - current number) exists without scanning the entire array.Final Answer:
To store numbers and their indices for quick lookup -> Option AQuick Check:
Hash map = quick index lookup [OK]
- Thinking hash map sorts the array
- Confusing hash map with storing sums
- Assuming hash map reverses elements
Solution
Step 1: Identify correct hash map syntax
std::unordered_map declares a hash map with int keys and int values.Step 2: Explain why others are incorrect
std::map<int> lacks value type; std::unordered_map<int> lacks value type; std::vector is invalid syntax.Final Answer:
std::unordered_map<int, int> map; -> Option BQuick Check:
Correct hash map syntax = std::unordered_map<int, int> [OK]
- Omitting value type in map declaration
- Using std::vector instead of map
- Confusing std::map and std::unordered_map syntax
nums = {2, 7, 11, 15} and target = 9?
std::vector<int> twoSum(std::vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (map.find(complement) != map.end()) {
return {map[complement], i};
}
map[nums[i]] = i;
}
return {};
}
int main() {
auto result = twoSum({2, 7, 11, 15}, 9);
for (int i : result) std::cout << i << " ";
}Solution
Step 1: Trace the loop and map updates
At i=0, map is empty, insert (2,0). At i=1, complement=9-7=2 found in map at index 0.Step 2: Return indices of complement and current
Return {0,1} which prints as "0 1".Final Answer:
[0 1] -> Option CQuick Check:
Indices of 2 and 7 = 0 and 1 [OK]
- Returning indices in wrong order
- Not checking complement before insertion
- Confusing values with indices
std::vector<int> twoSum(std::vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (map.find(complement) != map.end()) {
return {i, map[complement]};
}
map[nums[i]] = i;
}
return {};
}Solution
Step 1: Analyze the return statement order
The function returns {i, map[complement]} but correct order is {map[complement], i} to match indices.Step 2: Explain why swapping fixes the bug
Swapping ensures the first index is of complement and second is current index, matching problem requirement.Final Answer:
Swap the return indices to {map[complement], i} -> Option AQuick Check:
Correct index order = complement index, current index [OK]
- Returning indices in wrong order
- Inserting before checking complement
- Changing map type unnecessarily
nums = {3, 3, 4, 5} and target = 6, what will the classic Two Sum hash solution return and why?
std::vector<int> twoSum(std::vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (map.find(complement) != map.end()) {
return {map[complement], i};
}
map[nums[i]] = i;
}
return {};
}Solution
Step 1: Trace the loop with duplicates
At i=0, map empty, insert (3,0). At i=1, complement=6-3=3 found at index 0.Step 2: Return indices of first and second 3
Return {0,1} because nums[0] + nums[1] = 3 + 3 = 6.Final Answer:
[0 1] because first 3 and second 3 sum to 6 -> Option DQuick Check:
Duplicates allowed, indices 0 and 1 sum to target [OK]
- Ignoring duplicates in map
- Assuming no pair sums to target
- Returning indices in wrong order
Ready to prove it?
Pass the test and this pattern moves unknown
