哈希表(HashMap)算法总结
本文总结 LeetCode 上两道经典哈希表题目:两数之和 与 字母异位词分组。
一、两数之和(Two Sum)
题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那两个整数,并返回它们的数组下标。
假设每种输入只会对应一个答案,且不能使用同一个元素两次。
示例:
输入:nums = [2, 7, 11, 15], target = 9
输出:[0, 1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]
核心思路
暴力解法需要两层循环,时间复杂度 O(n²)。使用哈希表可以将时间复杂度降到 O(n)。
思想:遍历数组时,计算当前元素与目标值的差值 needNum = target – nums[i],检查这个差值是否已经存在于哈希表中:
- 如果存在 → 说明之前遍历过的某个元素 + 当前元素 = target,直接返回两个下标。
- 如果不存在 → 将当前元素的值和下标存入哈希表,继续遍历。
Java 代码
import java.util.HashMap;
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> maps = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int needNum = target – nums[i];
if (maps.containsKey(needNum)) {
return new int[]{maps.get(needNum), i};
}
maps.put(nums[i], i);
}
return new int[]{};
}
}
复杂度分析
| 时间复杂度 | O(n) — 只需一次遍历 |
| 空间复杂度 | O(n) — 哈希表最多存储 n 个元素 |
关键点
- HashMap 的 key 存值,value 存下标:因为要根据差值快速查找对应的下标。
- 先检查再存入:保证不会重复使用同一个元素(同一个元素只能使用一次)。
- 返回 new int[]{} 作为兜底,虽然题目保证一定有解。
二、字母异位词分组(Group Anagrams)
题目描述
给你一个字符串数组,请你将 字母异位词 组合在一起,返回结果列表。
字母异位词:由相同字母重新排列形成的字符串。例如 "eat" 和 "tea" 是字母异位词。
示例:
输入:strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:[["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]
核心思路
核心在于如何判断两个字符串是否为字母异位词。本质上是找到一种 统一的特征(key),让所有字母异位词映射到同一个 key 上。
方法:排序法
将每个字符串按字母排序,字母异位词排序后会得到完全相同的字符串。以这个排序后的字符串作为 key,将原始字符串归入对应的组。
Java 代码
import java.util.*;
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, List<String>> map = new HashMap<>();
for (String s : strs) {
char[] arr = s.toCharArray();
Arrays.sort(arr);
String key = new String(arr);
map.computeIfAbsent(key, k -> new ArrayList<>());
map.get(key).add(s);
}
return new ArrayList<>(map.values());
}
}
复杂度分析
| 时间复杂度 | O(n × k log k) — n 个字符串,每个长 k,排序 O(k log k) |
| 空间复杂度 | O(n × k) — 存储所有字符串 |
关键点
-
toCharArray() 将字符串转为字符数组,方便排序。
-
Arrays.sort(arr) 对字符数组排序,字母异位词排序后完全相同。
-
computeIfAbsent(key, k -> new ArrayList<>()):如果 key 不存在则创建新列表,存在则直接返回已有的列表。这行等价于:
if (!map.containsKey(key)) {
map.put(key, new ArrayList<>());
}
map.get(key).add(s); -
最后通过 new ArrayList<>(map.values()) 直接从 HashMap 的 values 构造结果列表。
三、哈希表解题模板总结
什么时候用哈希表?
| 快速查找 | 需要频繁判断某个元素是否存在,O(1) 查找 |
| 去重 / 计数 | 统计元素出现次数 |
| 分组 / 映射 | 建立键值对关系,将同类数据归组 |
| 降低复杂度 | 把 O(n²) 的双重循环优化到 O(n) |
常用技巧
| 值→下标 | 用 HashMap 存值和索引(如两数之和) |
| 特征→分组 | 将数据按某种特征(key)分组(如字母异位词分组) |
| computeIfAbsent | 简化 “不存在则新建” 的逻辑 |
| getOrDefault | 计数场景常用,不存在时返回默认值 |
四、小结
这两道题分别代表了哈希表最常见的两种应用场景:



