📖 哈希表专题怎么用?

哈希表用空间换时间——把 O(n²) 的查找降到 O(1)。面试中凡是"快速查找/计数"的题,第一反应就是哈希表。

本专题包含 4 道题,都是外企面试高频真题。每道题按统一结构讲解:

复习建议:先看生活类比理解问题本质,再看思路建立解题框架,最后手写代码 3 遍形成肌肉记忆。面试时先口述思路,确认无误后再写代码。

1两数之和 (Two Sum) Easy

题目(人话版)

给你一个数组 [2, 7, 11, 15] 和一个目标值 9。找到数组里哪两个数加起来等于 9,返回它们的下标。

答案:2 + 7 = 9,所以返回 [0, 1](2 在位置 0,7 在位置 1)。

💡 生活类比:你兜里有几张钞票 [2元, 7元, 11元, 15元],你想凑出 9 元买杯咖啡。怎么找? 最笨的方法:两张两张试(暴力法)。聪明的方法:每拿出一张,先算"我还需要多少"(9 - 2 = 还差 7),然后看 7 在不在兜里(哈希表)。

暴力思路(O(n²))

两个 for 循环,每对数字都试一遍。能做出来,但面试官会追问"能不能更快?"

优化思路:哈希表(O(n))

遍历到 2 还差 9-2=7 7 在 Map 里吗?不在 存入 Map{2:0}
遍历到 7 还差 9-7=2 2 在 Map 里吗?在!位置 0 返回 [0, 1]
twoSum.js
1
2
3
4
5
6
7
8
9
function twoSum(nums, target) { const map = new Map(); // 哈希表:存"值→下标" for (let i = 0; i < nums.length; i++) { const need = target - nums[i]; // 我还差多少? if (map.has(need)) { return [map.get(need), i]; // 找到了! } map.set(nums[i], i); // 没找到,把自己存进去 } }
方法时间空间面试评价
暴力双重循环O(n²)O(1)能做出来,但不够
哈希表一次遍历O(n)O(n)✅ 标准答案
面试加分项:主动说出"哈希表用空间换时间——多用了 O(n) 空间存 Map,但把时间从 O(n²) 降到 O(n)。" 然后追问:"如果数组是有序的,可以用双指针做到 O(1) 空间,但需要先排序 O(n log n)。" 这两句话一出,面试官就知道你真的懂。

2有效的字母异位词 (Valid Anagram) Easy

题目(人话版)

判断两个字符串是不是"字母异位词"——用的字母一模一样,只是顺序不同。"listen""silent" → ✅。"hello""world" → ❌。

💡 生活类比:就像两副拼图——碎片完全一样,只是拼出来的图案不同。验证方法:把两副都拆碎,数每种碎片有多少个,完全一样就是异位词。

方法一:排序比较法

anagram-sort.js
1
2
3
function isAnagram(s, t) { return s.split('').sort().join('') === t.split('').sort().join(''); } // "listen" → sort → "eilnst" // "silent" → sort → "eilnst" 相同!✅

一行代码,但排序要 O(n log n) 时间。

方法二:哈希表计数法(O(n))

anagram-count.js
1
2
3
4
5
6
7
8
9
10
11
12
function isAnagram(s, t) { if (s.length !== t.length) return false; const count = {}; // 字母 → 出现次数 for (const char of s) count[char] = (count[char] || 0) + 1; for (const char of t) { if (!count[char]) return false; // 这个字母不够了 count[char]--; } return true; }

时间 O(n),空间 O(1)(只有 26 个字母,哈希表大小固定)。

3数组去重/判断有重复 (Contains Duplicate) Easy

题目(人话版)

判断数组里有没有重复元素。[1,2,3,1]true(1 重复了)。[1,2,3,4]false

💡 生活类比:就像点名——每个人喊到的时候,你在花名册上打个勾。如果有人喊到时你发现已经勾过了——重复了!

方法一:Set 一行法(最简单)

hasDuplicate-set.js
1
2
3
function containsDuplicate(nums) { // Set 自动去重,去重后长度变短了 = 有重复 return new Set(nums).size !== nums.length; }

方法二:边遍历边检查(可以提前退出)

hasDuplicate-early.js
1
2
3
4
5
6
7
8
function containsDuplicate(nums) { const seen = new Set(); for (const num of nums) { if (seen.has(num)) return true; // 发现重复!立刻退出 seen.add(num); } return false; } // 优势:如果第2个就重复了,不用遍历完整个数组

两种都是 O(n) 时间 O(n) 空间。第二种可以提前退出。

面试追问:"能不能 O(1) 空间?" 答:先排序 O(n log n),然后遍历看相邻是否相同 O(1) 空间。但排序会改变原数组,要和面试官确认。

4第一个唯一字符 (First Unique Character) Easy

题目(人话版)

找字符串里第一个只出现一次的字符,返回它的下标。"loveleetcode" → 答案 2('v' 是第一个只出现一次的,下标 2)。

💡 生活类比:你在一群人里找"第一个没双胞胎的人"。怎么做?先数每个人有几个双胞胎(统计频率),然后再从左到右走一遍,第一个频率=1的就是答案。

思路:两遍遍历

第一遍:统计每个字母出现次数 第二遍:找到第一个次数=1的
firstUniqChar.js
1
2
3
4
5
6
7
8
9
10
11
12
function firstUniqChar(s) { const count = {}; // 第一遍:统计频率 for (const char of s) { count[char] = (count[char] || 0) + 1; } // 第二遍:找第一个频率=1的 for (let i = 0; i < s.length; i++) { if (count[s[i]] === 1) return i; } return -1; } // "loveleetcode" // count: {l:2, o:2, v:1, e:4, t:1, c:1, d:1} // 第一个 count=1 的是 v(下标 2)

时间 O(n),空间 O(1)(26 个字母,哈希表大小固定)。

为什么是两遍遍历?因为"第一个"是有顺序的——如果你只统计频率,不知道哪个在前哪个在后。必须第二遍按原始顺序走一遍,才能找到"第一个"符合条件的。

📋 哈希表专题速查表

#题目难度
1两数之和 (Two Sum)Easy
2有效的字母异位词 (Valid Anagram)Easy
3数组去重/判断有重复 (Contains Duplicate)Easy
4第一个唯一字符 (First Unique Character)Easy
考点核心:哈希表专题的核心就是"用对工具,降复杂度"。 面试时拿到题先想:"这道题能用哈希表吗?" 如果能,先说思路再写代码,面试官就知道你的分析能力。

🔗 其他考点专题

双指针专题:回文检测 (Valid Palindrome), 反转字符串 (Reverse String), 合并两个有序数组 (Merge Sorted Arrays), 移动零 (Move Zeroes)

动态规划专题:斐波那契数列 (Fibonacci), 爬楼梯 (Climbing Stairs), 最大子序和 (Max Subarray)

位运算专题:只出现一次的数字 (Single Number), 缺失数字 (Missing Number)

栈与滑动窗口专题:有效括号 (Valid Parentheses), 最长不重复子串 (Longest Substring)

综合技巧专题:FizzBuzz, 买卖股票的最佳时机 (Best Time to Buy/Sell Stock), 多数元素 (Majority Element), 旋转数组 (Rotate Array), 二分查找 (Binary Search)

← 返回图解算法与模式