Optimal Hash Table Implementations for Competitive Programming: A Cross-Language Guide from leetcode-master

The leetcode-master repository recommends using each language's built-in unordered hash map—such as std::unordered_map in C++, HashMap in Java, and dict in Python—to achieve O(1) average time complexity for lookups, insertions, and deletions in algorithm problems.

The youngyangyang04/leetcode-master repository is a comprehensive resource for algorithm interview preparation, providing solutions in over a dozen programming languages. When solving problems that require fast membership testing or frequency counting, selecting the optimal hash table implementation for your specific language is critical for meeting strict time complexity constraints on LeetCode.

Why Hash Tables Are Essential for Algorithm Problems

Hash tables provide O(1) average time complexity for insertions, deletions, and lookups, making them indispensable for problems involving two-sum pairs, anagram detection, and frequency analysis. According to the repository's hash table theory documentation in problems/哈希表理论基础.md, when you need to quickly determine if an element exists in a set, you should immediately consider hash-based solutions.

The author emphasizes that unordered containers offer superior performance to ordered alternatives: "当我们需要快速判断一个元素是否出现集合里,就要第一时间想到哈希法… 选择 std::unordered_map 效率更高!" (When we need to quickly determine whether an element appears in a collection, we should immediately think of the hash method... choosing std::unordered_map is more efficient!).

Optimal Hash Table Implementations by Language

The repository's canonical example in problems/0001.两数之和.md demonstrates the preferred hash table implementation for each supported language. Below are the specific recommendations with code excerpts extracted directly from the source files.

C++ – std::unordered_map

For C++, the repository explicitly recommends std::unordered_map over std::map because the former implements a hash table with O(1) average operations, while the latter uses a red-black tree with O(log n) complexity. The implementation in problems/0001.两数之和.md (lines 95-104) uses this container for the two-sum solution.

std::unordered_map<int,int> m;
for (int i = 0; i < nums.size(); ++i) {
    auto it = m.find(target - nums[i]);
    if (it != m.end()) return {it->second, i};
    m.emplace(nums[i], i);
}

Java – java.util.HashMap

Java solutions utilize java.util.HashMap as the default unordered map implementation. The code in problems/0001.两数之和.md (lines 40-49) demonstrates constant-time operations for membership testing.

Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
    int need = target - nums[i];
    if (map.containsKey(need)) return new int[]{map.get(need), i};
    map.put(nums[i], i);
}

Go – Built-in map

Go's native map type is a hash table with O(1) average performance. The repository uses it directly in problems/0001.两数之和.md (lines 88-96) without requiring external imports.

m := make(map[int]int)
for i, v := range nums {
    if j, ok := m[target-v]; ok {
        return []int{j, i}
    }
    m[v] = i
}

Python – dict

Python's dict is a highly optimized hash table. As shown in problems/0001.两数之和.md (lines 13-21), it provides the most concise syntax for the two-sum solution.

seen = {}
for i, v in enumerate(nums):
    if target - v in seen:
        return [seen[target - v], i]
    seen[v] = i

Rust – std::collections::HashMap

Rust's standard library provides HashMap with fast lookups. The implementation in problems/0001.两数之和.md (lines 4-7) pre-allocates capacity for efficiency.

use std::collections::HashMap;
let mut map = HashMap::with_capacity(nums.len());
for (i, &v) in nums.iter().enumerate() {
    if let Some(&j) = map.get(&(target - v)) {
        return vec![j as i32, i as i32];
    }
    map.insert(v, i);
}

JavaScript – Plain Object {}

JavaScript solutions use a plain object {} as a hash map because property access is O(1) and requires no imports. The code in problems/0001.两数之和.md (lines 44-50) demonstrates this pattern.

const hash = {};
for (let i = 0; i < nums.length; i++) {
    const need = target - nums[i];
    if (hash[need] !== undefined) return [hash[need], i];
    hash[nums[i]] = i;
}

TypeScript – Map<number, number>

TypeScript implementations utilize the ES6 Map object for explicit key-value semantics and type safety, as shown in problems/0001.两数之和.md (lines 58-70).

const mp = new Map<number, number>();
for (let i = 0; i < nums.length; i++) {
    const idx = mp.get(target - nums[i]);
    if (idx !== undefined) return [idx, i];
    mp.set(nums[i], i);
}

PHP – Associative Array []

PHP's associative arrays are hash tables under the hood. The solution in problems/0001.两数之和.md (lines 77-88) uses this native structure.

$map = [];
foreach ($nums as $i => $num) {
    $need = $target - $num;
    if (isset($map[$need])) return [$i, $map[$need]];
    $map[$num] = $i;
}

Swift – Dictionary<Int, Int>

Swift's Dictionary provides O(1) average lookups. The implementation in problems/0001.两数之和.md (lines 96-104) uses this type.

var dict = [Int:Int]()
for (i, v) in nums.enumerated() {
    if let j = dict[target - v] { return [j, i] }
    dict[v] = i
}

Scala – mutable.HashMap

Scala solutions use scala.collection.mutable.HashMap for constant-time mutable operations, as demonstrated in problems/0001.两数之和.md (lines 14-22).

val hm = scala.collection.mutable.HashMap[Int,Int]()
for (i <- nums.indices) {
  val need = target - nums(i)
  if (hm.contains(need)) return Array(hm(need), i)
  hm(nums(i)) = i
}

C# – Dictionary<int,int>

The .NET Dictionary implements a hash table with O(1) average performance. The code in problems/0001.两数之和.md (lines 38-46) demonstrates its usage.

var dict = new Dictionary<int,int>();
for (int i = 0; i < nums.Length; i++) {
    int need = target - nums[i];
    if (dict.TryGetValue(need, out int j)) return new []{j, i};
    dict[nums[i]] = i;
}

Dart – HashMap<int,int>

Dart's HashMap from dart:collection provides true hash-table semantics. The solution in problems/0001.两数之和.md (lines 56-64) uses this implementation.

final map = HashMap<int,int>();
for (int i = 0; i < nums.length; i++) {
  final need = target - nums[i];
  if (map.containsKey(need)) return [map[need]!, i];
  map[nums[i]] = i;
}

C – uthash Library

For C, which lacks a built-in hash table, the repository utilizes the uthash macro library. This portable implementation uses UT_hash_handle to manage hash buckets. The code in problems/0001.两数之和.md (lines 84-101) demonstrates this pattern.

typedef struct { int key, value; UT_hash_handle hh; } map;
map *hash = NULL;
for (int i = 0; i < n; ++i) {
    map *e; HASH_FIND_INT(hash, &nums[i], e);
    if (!e) { e = malloc(sizeof *e); e->key = nums[i]; e->value = i; HASH_ADD_INT(hash, key, e); }
}
for (int i = 0; i < n; ++i) {
    map *found; int need = target - nums[i];
    HASH_FIND_INT(hash, &need, found);
    if (found && found->value != i) return (int[]){i, found->value};
}

When to Use Arrays Instead of Hash Maps

While hash tables are the default choice for arbitrary keys, the repository demonstrates that arrays can serve as hash tables when the key domain is small and fixed. In problems/0242.有效的字母异位词.md, the solution uses a fixed-size array of 26 integers to count character frequencies rather than a hash map.

This approach eliminates hash function computation overhead and improves cache locality, but it only works when keys are constrained to a specific range (such as ASCII characters or small integers).

Summary

  • Optimal hash table implementations vary by language but consistently provide O(1) average time complexity for lookups, insertions, and deletions.
  • The leetcode-master repository demonstrates that you should always prefer unordered containers (like std::unordered_map, HashMap, or dict) over ordered tree-based structures unless sorting is required.
  • For languages without native hash tables (such as C), the uthash library provides a robust, portable solution.
  • When the key domain is restricted to a small fixed range (e.g., 26 letters), arrays can replace hash maps for better performance.

Frequently Asked Questions

Why does the repository recommend unordered_map over map in C++?

The repository explicitly recommends std::unordered_map over std::map because the former implements a hash table with O(1) average operations, while the latter uses a red-black tree with O(log n) complexity. For LeetCode problems that only require existence checks or frequency counting without sorted traversal, the hash table implementation provides superior performance and is the optimal choice.

Can I use a plain array instead of a hash map in every language?

No, arrays are only suitable when the key domain is small and fixed, such as counting occurrences of lowercase English letters (26 characters) or digits (0-9). The repository demonstrates this pattern in problems/0242.有效的字母异位词.md for anagram problems. For arbitrary integer ranges or string keys, a proper hash table implementation is required to avoid excessive memory usage and collision handling issues.

What is the time complexity guarantee for these hash table implementations?

All implementations presented in the repository provide O(1) average time complexity for insertions, deletions, and lookups under normal conditions. However, in worst-case scenarios where all keys collide, complexity degrades to O(n). The repository notes that LeetCode's test data is typically designed to avoid such pathological cases, making these hash tables reliable for competitive programming constraints.

How does the C implementation using uthash compare to native implementations?

The uthash library used in the C implementation provides macro-based hash table functionality that is portable and efficient, though it requires manual memory management. Unlike native implementations in higher-level languages, uthash does not provide automatic resizing or garbage collection, but it still achieves O(1) average operations. The repository includes this in problems/0001.两数之和.md to demonstrate that C developers can achieve comparable performance to modern languages using well-tested third-party libraries.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →