HASHING AND HASH TABLES ======================= A hash table stores key-value pairs. Uses a hash function to map keys to indices. Average time: O(1) for insert, delete, search. Worst case: O(n) with collisions. Python's dict and set are hash tables. --- Hash Table Basics --- # Python dict = hash map phone_book = {} phone_book["Alice"] = "555-1234" phone_book["Bob"] = "555-5678" print(phone_book["Alice"]) # "555-1234" print("Alice" in phone_book) # True del phone_book["Bob"] print(phone_book.get("Bob", "N/A")) # "N/A" # Iterate for name, number in phone_book.items(): print(name, number) --- Build a Hash Map from Scratch --- class HashMap: def __init__(self, size=1000): self.size = size self.buckets = [[] for _ in range(size)] def _hash(self, key): return hash(key) % self.size def put(self, key, value): idx = self._hash(key) for i, (k, v) in enumerate(self.buckets[idx]): if k == key: self.buckets[idx][i] = (key, value) return self.buckets[idx].append((key, value)) def get(self, key): idx = self._hash(key) for k, v in self.buckets[idx]: if k == key: return v return None def remove(self, key): idx = self._hash(key) self.buckets[idx] = [(k, v) for k, v in self.buckets[idx] if k != key] hm = HashMap() hm.put("name", "Alice") hm.put("age", 25) print(hm.get("name")) # Alice hm.remove("age") print(hm.get("age")) # None --- Two Sum Problem --- Find two numbers that add up to target. Classic hash map problem. Time: O(n). Space: O(n). def two_sum(nums, target): seen = {} # value → index for i, num in enumerate(nums): complement = target - num if complement in seen: return [seen[complement], i] seen[num] = i return [] print(two_sum([2, 7, 11, 15], 9)) # [0, 1] print(two_sum([3, 2, 4], 6)) # [1, 2] --- Group Anagrams --- Group words that are anagrams of each other. Time: O(n * k log k) where k = max word length. from collections import defaultdict def group_anagrams(words): groups = defaultdict(list) for word in words: key = ''.join(sorted(word)) # sorted chars as key groups[key].append(word) return list(groups.values()) print(group_anagrams(["eat","tea","tan","ate","nat","bat"])) # [["eat","tea","ate"], ["tan","nat"], ["bat"]] --- Frequency Counter --- Count frequency of each element. from collections import Counter def top_k_frequent(nums, k): count = Counter(nums) return [x for x, _ in count.most_common(k)] print(top_k_frequent([1,1,1,2,2,3], 2)) # [1, 2] --- Longest Consecutive Sequence --- Find length of longest consecutive elements sequence. Time: O(n). Space: O(n). def longest_consecutive(nums): num_set = set(nums) best = 0 for num in num_set: if num - 1 not in num_set: # start of sequence length = 1 while num + length in num_set: length += 1 best = max(best, length) return best print(longest_consecutive([100,4,200,1,3,2])) # 4 (1,2,3,4) --- Subarray Sum Equals K --- Count subarrays with sum equal to k. Uses prefix sum + hash map. Time: O(n). Space: O(n). def subarray_sum(nums, k): count = 0 prefix = 0 freq = {0: 1} # prefix_sum → frequency for num in nums: prefix += num if prefix - k in freq: count += freq[prefix - k] freq[prefix] = freq.get(prefix, 0) + 1 return count print(subarray_sum([1, 1, 1], 2)) # 2 print(subarray_sum([1, 2, 3], 3)) # 2 --- Check if Two Strings are Anagram --- def is_anagram(s, t): return Counter(s) == Counter(t) print(is_anagram("anagram", "nagaram")) # True print(is_anagram("rat", "car")) # False --- First Non-Repeating Character --- def first_unique(s): count = Counter(s) for i, ch in enumerate(s): if count[ch] == 1: return i return -1 print(first_unique("leetcode")) # 0 (l) print(first_unique("aabb")) # -1 --- Hash Set Uses --- # O(1) membership test visited = set() visited.add(5) print(5 in visited) # True print(10 in visited) # False # Remove duplicates arr = [1, 2, 2, 3, 3, 4] unique = list(set(arr)) print(unique) # [1, 2, 3, 4] # Intersection, Union a = {1, 2, 3, 4} b = {3, 4, 5, 6} print(a & b) # {3, 4} intersection print(a | b) # {1,2,3,4,5,6} union print(a - b) # {1, 2} difference