Skip to content

Hash Table

Use a hash function to map keys to array positions — Makes lookups nearly O(1)


Concept

Real-Life Analogy

** Mailboxes**: An apartment building has numbered mailboxes. The mail carrier uses a formula to figure out which box gets which letter — no need to check every box.

More examples:

  • Library indexing: Book title → shelf number
  • Database indexing: Fast row lookup by key
  • Caching systems: Direct access by key

Dictionary vs Hash Table

In the Dictionary chapter, we used a plain JS object. With a Hash Table, we build it ourselves so you can see exactly how it works:

  1. Hash function — turns a key into an array index
  2. Collision resolution — what happens when two keys map to the same spot
  3. Dynamic resizing — grows when it gets too full

Code

javascript
class HashTable {
  constructor() {
    this.storage = []
    this.count = 0
    this.limit = 7 // start with a prime number
  }

  // Hash function: key → array index
  hashFunc(str, size) {
    let hashCode = 0
    // Horner's method: efficient polynomial evaluation
    for (let i = 0; i < str.length; i++) {
      hashCode = 37 * hashCode + str.charCodeAt(i)
    }
    return hashCode % size
  }

  // Insert or update
  put(key, value) {
    const index = this.hashFunc(key, this.limit)
    let bucket = this.storage[index]
    if (!bucket) {
      bucket = []
      this.storage[index] = bucket
    }
    // Check if key already exists → update
    for (let i = 0; i < bucket.length; i++) {
      if (bucket[i][0] === key) {
        bucket[i][1] = value
        return
      }
    }
    // New key → add to bucket
    bucket.push([key, value])
    this.count++
    // Resize if load factor > 0.75
    if (this.count > this.limit * 0.75) {
      this._resize(this._getPrime(this.limit * 2))
    }
  }

  // Get value by key
  get(key) {
    const index = this.hashFunc(key, this.limit)
    const bucket = this.storage[index]
    if (!bucket) return null
    for (let i = 0; i < bucket.length; i++) {
      if (bucket[i][0] === key) return bucket[i][1]
    }
    return null
  }

  // Remove by key
  remove(key) {
    const index = this.hashFunc(key, this.limit)
    const bucket = this.storage[index]
    if (!bucket) return null
    for (let i = 0; i < bucket.length; i++) {
      if (bucket[i][0] === key) {
        const value = bucket[i][1]
        bucket.splice(i, 1)
        this.count--
        // Shrink if load factor < 0.25
        if (this.limit > 7 && this.count < this.limit * 0.25) {
          this._resize(this._getPrime(Math.floor(this.limit / 2)))
        }
        return value
      }
    }
    return null
  }

  isEmpty() {
    return this.count === 0
  }
  size() {
    return this.count
  }

  // Resize and rehash all elements
  _resize(newLimit) {
    const oldStorage = this.storage
    this.storage = []
    this.count = 0
    this.limit = newLimit
    for (let i = 0; i < oldStorage.length; i++) {
      const bucket = oldStorage[i]
      if (bucket) {
        for (let j = 0; j < bucket.length; j++) {
          this.put(bucket[j][0], bucket[j][1])
        }
      }
    }
  }

  // Prime number helpers — prime sizes reduce collisions
  _isPrime(num) {
    if (num < 2) return false
    const sqrt = Math.sqrt(num)
    for (let i = 2; i <= sqrt; i++) {
      if (num % i === 0) return false
    }
    return true
  }

  _getPrime(num) {
    while (!this._isPrime(num)) num++
    return num
  }
}

Key Points

ConceptExplanation
Hash functionHorner's method turns strings into numbers, then % size to fit the array
ChainingEach array position holds a "bucket" (array) for collisions
Load factorcount / limit — resize when > 0.75, shrink when < 0.25
Prime sizeArray length stays prime to reduce collisions
RehashingOn resize, ALL elements get new positions

Complexity

OperationAverageWorstNotes
put()O(1)O(n)Bad hash = many collisions
get()O(1)O(n)
remove()O(1)O(n)
ResizeO(n)O(n)Rehash everything

Interview Questions

1. First Unique Character

javascript
function firstUniqChar(s) {
  const ht = new HashTable()
  for (const char of s) {
    const count = ht.get(char) || 0
    ht.put(char, count + 1)
  }
  for (let i = 0; i < s.length; i++) {
    if (ht.get(s[i]) === 1) return i
  }
  return -1
}

console.log(firstUniqChar('leetcode')) // 0
console.log(firstUniqChar('aabb')) // -1

Summary

PropertyDescription
Core ideaHash function + array + chaining
Key opsput / get / remove — O(1) average
3 essentialsHash function, collision handling, dynamic resizing
vs DictionaryDictionary wraps JS object; HashTable is built from scratch
NextBinary Search Tree — Sorted tree structure

LeetCode Practice

#ProblemDifficulty
1Two SumEasy
3Longest Substring Without RepeatingMedium

Back to Set · Back to Home

MIT Licensed | Made with ❤️ for JS learners