引言
哈希表是最常用的数据结构之一,提供O(1)的查找、插入和删除操作。本文深入讲解哈希表原理和经典应用。
一、哈希表基础
1.1 哈希表原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| public class SimpleHashMap<K, V> { private static class Entry<K, V> { K key; V value; Entry<K, V> next; Entry(K key, V value) { this.key = key; this.value = value; } } private Entry<K, V>[] table; private int size; private static final int DEFAULT_CAPACITY = 16; @SuppressWarnings("unchecked") public SimpleHashMap() { table = new Entry[DEFAULT_CAPACITY]; } private int hash(K key) { return Math.abs(key.hashCode() % table.length); } public void put(K key, V value) { int index = hash(key); Entry<K, V> newEntry = new Entry<>(key, value); if (table[index] == null) { table[index] = newEntry; } else { Entry<K, V> current = table[index]; while (true) { if (current.key.equals(key)) { current.value = value; return; } if (current.next == null) { current.next = newEntry; break; } current = current.next; } } size++; } public V get(K key) { int index = hash(key); Entry<K, V> current = table[index]; while (current != null) { if (current.key.equals(key)) { return current.value; } current = current.next; } return null; } }
|
1.2 哈希冲突解决
1. 链地址法(Chaining)
2. 开放寻址法(Open Addressing)
1 2 3 4 5
| int index = hash(key); while (table[index] != null) { index = (index + 1) % table.length; }
|
二、哈希表经典题目
2.1 两数之和(LeetCode 1)
1 2 3 4 5 6 7 8 9 10 11 12 13
| public int[] twoSum(int[] nums, int target) { Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int complement = target - nums[i]; if (map.containsKey(complement)) { return new int[]{map.get(complement), i}; } map.put(nums[i], i); } return new int[]{}; }
|
2.2 字母异位词分组(LeetCode 49)
1 2 3 4 5 6 7 8 9 10 11 12 13
| public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (String str : strs) { char[] chars = str.toCharArray(); Arrays.sort(chars); String key = String.valueOf(chars); map.computeIfAbsent(key, k -> new ArrayList<>()).add(str); } return new ArrayList<>(map.values()); }
|
2.3 最长连续序列(LeetCode 128)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public int longestConsecutive(int[] nums) { Set<Integer> set = new HashSet<>(); for (int num : nums) { set.add(num); } int maxLength = 0; for (int num : set) { if (!set.contains(num - 1)) { int currentNum = num; int currentLength = 1; while (set.contains(currentNum + 1)) { currentNum++; currentLength++; } maxLength = Math.max(maxLength, currentLength); } } return maxLength; }
|
三、总结
哈希表核心:
- O(1)操作:查找、插入、删除
- 冲突解决:链地址法、开放寻址
- 应用场景:去重、计数、缓存
参考资料