Using a Hash Table | LeetCode#1 Two Sum
🌐 中文版:繁體中文
Problem statement

The problem gives an integer array and an integer target, and asks us to find any two elements in the array that add up to target and return their indices. Also, each input array has exactly one output answer.
Solution 1: brute force
As usual, we start with brute force: get a solution first, then see how to optimize later.
1 | /** |
The core approach here is: pick one element, compare it against another element, and see whether the sum is target.
But doing this has a time complexity of $O(n^2)$.
Also, since the problem requires the returned array to be dynamically allocated, we must free the memory address at the end. *returnSize is used to tell the caller the size of the returned array. Since C doesn’t support returning multiple values directly, the problem needs a pointer to modify an external variable, which lets us pass more information.
Execution result:

Solution 2: using a hash table
1 | /** |
The main flow of the program is:
- Define the hashtable structure and the hashtable size
- Define the hash function
- Initialize the return array
- Initialize the hashtable
- Insert elements, first checking whether an element already exists at the index
- When a collision happens, handle it with linear probing to find an empty slot
- If no element exists, insert the element directly
- Free memory and return the result array
This approach is also called a two-pass hash table, mainly because it iterates twice: once to fill each element’s value and index into the hashtable’s key and value, and once to check whether each element’s complement exists in the hash table.
This way, using a hash table, the runtime complexity can drop to $O(n)$. Looking up a hash table is actually $O(1)$, but accounting for possible collisions and the linear probing, the overall time complexity becomes $O(n)$.

Reflection
When I was first implementing this, my original hashtable structure only defined
1 | typedef struct{ |
and in the condition I used while( hashtable[index].key != 0 || hashtable[index].value != 0 ).
But later I found this had problems with certain test cases, like when nums = [0,4,3,0] and target = 0, there wouldn’t be any output.
Problem analysis
The reason is that when inserting into the hash table, taking the first element as an example, the key inserted into the hashtable would be 0. But we defined the no-data state as 0 during initialization, and in the middle condition we also used 0 as the basis for judging whether a slot has a value. So when the value we actually want to store is itself 0, there’s a conflict. The subsequent fix was therefore to define a hasData field in the hashtable structure to judge whether data exists.
But doing this also has a downside: it increases the space complexity.
Another solution: one-pass hash
1 | int* twoSum(int* nums, int numsSize, int target, int* returnSize) { |
Here we merge inserting into the hashtable and checking the complement into the same iteration. But since we still iterate over n elements, the time complexity is still $O(n)$.
At this point I also started thinking about switching to C++ for LeetCode, lol. For a problem like this, C++ has a lot of handy STL like
unordered_mapyou can use directly, without having to redesign much.
C++ solution
1 | class Solution { |








