在 LeetCode 的题目体系中,哈希表(Hash Table) 是最常见、最重要的数据结构之一。
它的核心优势是:
用空间换时间,将查找复杂度从 O(n) 降到 O(1)。
很多面试高频题都离不开哈希表的思想。
本篇博客将系统总结三道最经典的哈希表入门题:
-
1. 两数之和(Two Sum)
-
49. 字母异位词分组(Group Anagrams)
-
128. 最长连续序列(Longest Consecutive Sequence)
并通过这三题掌握哈希表最核心的三种用法:
✅ 查补数
✅ 分组映射
✅ 连续序列判断
一、LeetCode 1:两数之和(Two Sum)
1. 题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你找出数组中 和为 target 的两个数,并返回它们的下标。
示例
bash
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:nums[0] + nums[1] = 2 + 7 = 9
2. 暴力思路(不可取)
最直观的方法是双重循环:
cpp
for i:
for j:
if nums[i] + nums[j] == target
时间复杂度:
bash
O(n²)
当 n 达到 10⁵ 时直接超时。
3. 哈希表优化思路
核心思想:查找补数
遍历数组时:
-
当前数字为
x -
需要另一个数字
need = target - x
如果之前出现过 need,说明答案已找到。
因此我们使用哈希表:
-
key:数字
-
value:数字出现的位置
4. C++代码实现
cpp
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> mp;
for (int i = 0; i < nums.size(); i++) {
int need = target - nums[i];
if (mp.count(need)) {
return {mp[need], i};
}
mp[nums[i]] = i;
}
return {};
}
};
5. 复杂度分析
|------|--------|
| 操作 | 复杂度 |
| 遍历数组 | O(n) |
| 哈希查找 | O(1) |
| 总复杂度 | ✅ O(n) |
二、LeetCode 49:字母异位词分组(Group Anagrams)
1. 题目描述
给定字符串数组 strs,请你将所有 字母异位词 分组。
字母异位词:
-
字母相同
-
顺序不同
示例
bash
输入:["eat","tea","tan","ate","nat","bat"]
输出:
[
["eat","tea","ate"],
["tan","nat"],
["bat"]
]
2. 哈希表的核心:分类映射
异位词的本质
两个字符串是异位词:
排序后一定完全相同。
例如:
|------|-----|
| 原字符串 | 排序后 |
| eat | aet |
| tea | aet |
| ate | aet |
因此可以用:
-
key:排序后的字符串
-
value:所有属于该 key 的字符串集合
3. 解题步骤
-
遍历字符串数组
-
对每个字符串排序得到 key
-
放入哈希表中分类
-
最后输出所有组
4. C++代码实现
cpp
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for (auto& s : strs) {
string key = s;
sort(key.begin(), key.end());
mp[key].push_back(s);
}
vector<vector<string>> result;
for (auto& p : mp) {
result.push_back(p.second);
}
return result;
}
};
5. 复杂度分析
设:
-
n 为字符串数量
-
k 为字符串平均长度
排序复杂度:
bash
O(k log k)
总复杂度:
bash
O(n * k log k)
三、LeetCode 128:最长连续序列(Longest Consecutive Sequence)
1. 题目描述
给定一个未排序整数数组 nums,找出数字连续的最长序列长度。
要求算法复杂度必须为:
bash
O(n)
示例
bash
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长连续序列是 [1,2,3,4]
2. 核心难点
排序可以解决:
cpp
sort(nums)
但复杂度:
cpp
O(n log n)
题目要求必须 O(n)。
3. 哈希集合解法:从起点扩展
核心思想
如果数字 x 是一个连续序列的起点:
bash
x - 1 不存在
例如:
序列 [1,2,3,4]
起点只有 1,因为:
- 1-1 = 0 不存在
所以:
-
用
unordered_set存所有数字 -
只从起点开始扩展
-
每个数字最多访问一次
4. C++代码实现
cpp
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> st(nums.begin(), nums.end());
int longest = 0;
for (int x : st) {
// 只有当 x 是起点才扩展
if (!st.count(x - 1)) {
int cur = x;
int len = 1;
while (st.count(cur + 1)) {
cur++;
len++;
}
longest = max(longest, len);
}
}
return longest;
}
};
5. 复杂度分析
|------|--------|
| 操作 | 复杂度 |
| 建集合 | O(n) |
| 扩展遍历 | O(n) |
| 总复杂度 | ✅ O(n) |
四、三题核心套路总结
|-----|---------------------|--------------------------------|------|
| 题号 | 题目 | 哈希结构 | 核心思想 |
| 1 | Two Sum | unordered_map | 查补数 |
| 49 | Group Anagrams | unordered_map<string,vector> | 分类映射 |
| 128 | Longest Consecutive | unordered_set | 起点扩展 |
五、哈希表题目三大模板
模板 1:查找补数
cpp
need = target - x;
if (mp.count(need)) return ans;
模板 2:分类映射
cpp
key = transform(x);
mp[key].push_back(x);
模板 3:存在性判断 + 起点扩展
cpp
if (!st.count(x-1)) {
while(st.count(x+1)) ...
}
六、总结
通过这三道经典题,你应该掌握哈希表在 LeetCode 中最常见的三种用途:
✅ 快速查找
✅ 分类分组
✅ 判断连续关系
哈希表题目看似简单,但却是面试必考的基础能力。
📌 下一步推荐练习(哈希专题)
如果你想继续刷哈希题,可以按顺序练:
-
217 存在重复元素
-
242 有效的字母异位词
-
560 和为 K 的子数组
-
347 前 K 个高频元素
-
15 三数之和(哈希 + 双指针)