吃透LeetCode Hot 100:三轮刷题法打造算法面试竞争力
LeetCode Hot 100这份题单,我前前后后刷了三轮,每次刷都有新的理解。它不只是一份“面试高频题列表”,更像一张算法能力地图,覆盖了数组、链表、树、图、动态规划、贪心、回溯这些核心考点。不管你是准备校招、社招,还是单纯想把算法底子打扎实,Hot 100都是绕不开的起点。这篇文章我就从题集拆解、刷题路线、典型题目实战、常见坑点这几个维度,把这份题单彻底讲透。
很多人在初刷的时候容易陷入一个误区:想把每道题的解法背下来,或者一遍AC才肯罢休。实际上,Hot 100的价值在于让你用有限的时间建立“题型识别”能力,看到一个题能快速判断它属于哪类模型,然后套用对应的套路。所以这篇文章不只是罗列题目,我会重点讲“怎么刷”和“为什么这么刷”,配合具体题目做拆解,争取让你看完之后可以直接照着执行。
1. Hot 100到底是什么,为什么成了刷题标配
1.1 题集的来源与边界
Hot 100是LeetCode官方根据站内题目热度、提交量、面试出现频率综合排序出来的100道题,准确说是“热门100题”。它不是固定的“题库”,而是动态更新的榜单,每隔一段时间会随着用户做题数据和新增题目调整。所以你会看到网上有人整理的“hot100题解pdf”版本不同,就是因为他们截取的是不同时间段的榜单。
这份题单最大的特点是高频。它抓取的是大多数人在面试里真实遇到的题,不是偏题怪题,也不是纯炫技题。对比LeetCode全部2800多道题,Hot 100的体量很小,但覆盖面足够广。什么叫“边界”?就是它解决的是“从零到一”的问题——帮你在有限时间内把最重要的算法思想过一遍,而不是让你把所有题目都刷完。
另外要注意,Hot 100和LeetCode周赛是两码事。周赛题目偏思维、偏技巧,适合在基础扎实之后去挑战;而Hot 100偏向基础功,考的是常见数据结构和经典算法模式。我看到热词里有“leetcode周赛430”,如果你Hot 100还没过完一遍,建议先别急着冲周赛,否则容易受挫。
1.2 刷Hot 100能解决什么问题
简单说,它解决的三个核心问题是:不知道刷什么、不知道刷到什么程度、刷完不知道有什么用。
先说“不知道刷什么”。很多新手打开LeetCode,按难度从Easy到Hard往下刷,刷到200题发现很多题重复度极高,纯属浪费时间。Hot 100帮你把最高频的题挑出来,省去筛选成本。
再说“刷到什么程度”。Hot 100的题目难度分布很合理,Easy大约占三成,Medium占五成以上,Hard只有不到两成。这个分布刚好匹配面试需求:Easy用来热身和考基础,Medium是主流,Hard考察深度。你把Hot 100里的Medium题吃透,面试遇到中等题基本能稳住。
最后,“刷完有什么用”。刷完Hot 100,你会建立起自己的“算法模板库”,比如二分查找的边界写法、滑动窗口的框架、树上DFS的递归套路、动态规划的做备忘录方法。这些模板可以迁移到其他题目上,后续再刷500题、1000题,都是在往这个框架上添砖加瓦。
2. 题型构成与能力地图:先从整体看到局部
2.1 按数据结构拆解:数组、链表、树、图
如果你把Hot 100的题目按数据结构分桶,会发现分布非常集中。我大概统计过自己刷过的版本,数组和字符串相关的题最多,能占到30%以上;树和二叉树相关的题排第二,大概20%;链表大概10%;图和搜索的问题大概15%;剩下的分布在堆、栈、哈希表等结构上。
数组和字符串多,是因为它们是最基础的数据载体,双指针、滑动窗口、哈希表优化、前缀和这些技巧都建立在数组之上。链表题虽然数量少,但考的几乎是固定套路:反转链表、快慢指针找环、合并有序链表、删除倒数第N个节点。树的问题则是递归的训练场,前中后序遍历、层序遍历、最近公共祖先、路径总和,本质都在考“递归终止条件”和“单层处理逻辑”。
图的问题难度更高,Hot 100里的图题通常以岛屿类(DFS/BFS)和拓扑排序为主,比如岛屿数量、课程表。这些题从模板上讲,难度并不在于代码量,而在于你是否能把问题抽象成图。举个例子,课程表问题其实是检测有向图是否存在环,你能看到这一点,代码只是套模板。
2.2 按算法思想拆解:二分、双指针、动态规划、回溯
换个角度,从算法思想来分桶,Hot 100最值钱的部分集中在下面几类。
二分查找。Hot 100里的二分题不多,但每一道都很典型,比如搜索旋转排序数组、在排序数组中查找元素的第一个和最后一个位置、爱吃香蕉的狒狒。二分考的其实是“单调性”,只要你能找到一个随某个变量单调变化的函数,就可以用二分来逼近答案。
双指针和滑动窗口。这是面试最爱考的一类,典型题有盛最多水的容器、三数之和、无重复字符的最长子串、最小覆盖子串。双指针的精髓是“利用有序性减少枚举”,滑动窗口的精髓是“维护一个满足条件的窗口,通过移动左右边界找到最优解”。这类题一旦掌握模板,几乎可以秒杀同类题。
动态规划。Hot 100里的DP题占了相当大的比重,包括爬楼梯、打家劫舍、最长递增子序列、编辑距离、零钱兑换等。做DP题的核心是先定义状态,再写转移方程,最后处理边界条件。开头会感觉很难,但你把十来道经典DP题吃透,会发现翻来覆去就是那些套路。
回溯。全排列、组合总和、子集、括号生成,这些是回溯的标准题型。回溯的框架很固定:路径、选择列表、终止条件,然后做选择和撤销选择。难点在于剪枝,剪枝剪得好不好,直接决定能不能通过大数据量测试。
2.3 从Hot 100延伸出去
Hot 100不是终点,它是一个起点。当你把这份题单刷透,会发现自己具备了识别“题眼”的能力,这时候再去看LeetCode周赛(比如热词里提到的周赛430),或者去刷剑指Offer、其他热门题单,就会发现新题不再是完全陌生的。
我们常说“刷题刷的是思路,不是题目本身”。Hot 100的题目是经过筛选的“母题”,掌握了这些母题的解法,很多新题都能归约到已知模型上。所以我的建议是:不要执着于“把Hot 100背下来”,而是每刷完一题,问问自己“这题属于哪个模型?和之前哪道题类似?有什么不同?”
3. 三轮刷题法:把100题真正吃透
3.1 第一轮:按标签刷,建立肌肉记忆
第一轮的目标是建立对算法的整体感知,不需要追求“独立AC”,遇到不会的题直接看题解完全没有问题。关于“hot100题解pdf”这类资源,建议不要一上来就抱着PDF从头看到尾,这样很容易看一个忘一个。正确做法是:每道题先独立思考10到15分钟,如果完全没有思路,直接打开题解看思路,然后把题解关掉,自己动手把代码写出来。
第一轮我建议按算法类型分组刷。比如用一周时间专门刷链表题,下一周专门刷树题,再下一周专门刷DP题。这样做的好处是,你能在同一段时间内反复接触同一类套路,形成肌肉记忆。比如你连续刷10道树题,递归写多了,看到树不会再慌。
时间安排上,如果每天能抽出2到3小时,大概能刷5到8道题,第一轮大约半个月到三周可以过完。第一轮不用太纠结时间复杂度和空间复杂度,先把AC当作目标,把每个解法跑通再说。
3.2 第二轮:按题型交叉刷,训练识别能力
第二轮的目标是“去标签化”,训练你看到题目就能自己判断用哪种算法的能力。这时候不要再按算法分组刷题了,而是打乱顺序,或者直接使用LeetCode的随机选题功能。给自己定一个规矩:看到题先不写代码,先用两句话口头说清思路,比如“这题是二分查找,先排序,再对答案进行二分”,然后再动手敲。
这一轮还要开始做“错题本”。我自己的做法是用表格登记:题目编号、题名、我的思路卡在哪、题解思路、复刷时间。这个表格比任何题解PDF都重要,因为它记录的是你个性化的薄弱点。
第二轮遇到卡壳的时候,先别急着看题解,试着自己画测试用例走一遍代码逻辑。很多时候卡住是因为对边界条件不够敏感,比如二分查找里
left <= right
还是
left < right
,滑动窗口里窗口什么时候收缩。这些细节在第一轮可能靠查模板过关,第二轮要自己推明白。
3.3 第三轮:模拟面试与随机抽查
第三轮的目标是实战状态。把LeetCode的面试模拟功能用起来,或者找个朋友互相出题,严格按45分钟一道Medium题的标准来。这一轮不追求刷题数量,而是追求“稳”。很多人在独立刷题时能AC,一到面试现场就大脑空白,核心原因是缺乏“口头讲题”训练。
所以第三轮每次做题,都要打开录音或者对着镜子,先说清楚:第一,这个题的输入输出是什么;第二,暴力解法怎么做,复杂度多少;第三,能不能优化,怎么优化;第四,代码写完后逐行过一遍边界条件。这套流程在面试里非常加分,因为面试官更看重的是你“思考的过程”,而不只是最终答案。
到了这一轮,建议同时参加LeetCode周赛(比如热词里提到的周赛430)来检验水平。周赛的题目通常比面试题更绕,但参加周赛能帮你锻炼在压力下读题、建模、编码的能力。哪怕周赛只AC一道题,也比你在舒适区里刷十道题有价值。
4. 高频题目实战拆解:从模板到思路
4.1 二分查找模板:爱吃香蕉的狒狒这类题怎么一眼看穿
热词里有一个很典型的题目“leetcode 073爱吃香蕉的狒狒”,这就是LeetCode 875题。这道题非常经典,因为它是二分查找的变体——对答案做二分,而不是对数组下标做二分。
题目大意是:有N堆香蕉,每堆香蕉的根数已知,狒狒每小时吃一堆香蕉中的K根,如果一堆少于K根就全吃完。问在H小时内吃完所有香蕉的最小速度K是多少。
最直接的思路是从1开始枚举速度,检查是否能在H小时内吃完,显然太慢。观察到一个关键性质:如果速度K能在H小时内吃完,那么任何大于K的速度也一定能吃完;如果K不能,任何小于K的速度也不能。这满足“单调性”,所以可以对速度K做二分查找。
def minEatingSpeed(piles, h):
def can_finish(k):
hours = 0
for p in piles:
hours += (p + k - 1) // k
return hours <= h
left, right = 1, max(piles)
while left < right:
mid = (left + right) // 2
if can_finish(mid):
right = mid
else:
left = mid + 1
return left
这里的计算方式
(p + k - 1) // k
是向上取整,用来模拟“每堆要吃几小时”。很多人在写这类二分时容易搞混
left = mid + 1
和
right = mid
的移动方向。记住一个口诀:满足条件就往左收,不满足就往右收。这道题里,速度够快就说明答案可能更小,所以
right = mid
;速度不够就说明答案必须更大,所以
left = mid + 1
。
这类“求最小可行值”或者“最大可行值”的题目,本质都是二分查找,典型题还有:分割数组的最大值、运货能力、每个厨师做菜的最短时间等。你只要识别出“可行解具有单调性”,就可以套模板。
4.2 双指针与滑动窗口:链表和数组题的常客
Hot 100里的双指针题值得单独拎出来说。比如“盛最多水的容器”和“三数之和”用的是左右指针,“无重复字符的最长子串”和“最小覆盖子串”用的是滑动窗口。
以“盛最多水的容器”为例,两根柱子围成的面积等于
min(height[left], height[right]) * (right - left)
。朴素的枚举所有组合是O(n^2),但用双指针可以做到O(n)。核心思路是:每次移动高度较矮的那一端,因为只有移动矮的,才有可能让面积变大;移动高的那端,面积只会受限于更矮的柱子,不可能变得更大。这个思路就源于“问题具有某种单调趋势”。
再看“无重复字符的最长子串”,滑动窗口的模板可以提炼成三步:
- 右指针不断向右扩展,加入新字符;
- 如果窗口内出现重复字符,左指针向右移动,直到没有重复;
- 每次窗口合法时更新答案。
def lengthOfLongestSubstring(s):
window = set()
left = 0
ans = 0
for right, ch in enumerate(s):
while ch in window:
window.remove(s[left])
left += 1
window.add(ch)
ans = max(ans, right - left + 1)
return ans
这个模板可以迁移到很多题上,比如“长度最小的子数组”,区别只是循环里的“窗口收缩条件”不同。很多人对滑动窗口产生恐惧,是因为没有形成模板意识。实际上滑窗题有四个要素:窗口内维护什么数据、左指针什么时候收缩、右指针怎么扩展、什么时候更新答案。对照这四个要素去做题,思路会清晰很多。
4.3 动态规划题怎么打表
Hot 100里的DP题看着五花八门,核心就是把“大问题拆成小问题,小问题的答案存起来复用”。以“打家劫舍”为例,你是一个小偷,不能偷相邻的两个房子,问最多能偷多少。
定义
dp[i]
表示前i个房子能偷到的最大值。对于第i个房子,有两种选择:不偷,那么
dp[i] = dp[i-1]
;偷,那么
dp[i] = dp[i-2] + nums[i]
。取两者的最大值即可:
def rob(nums):
if not nums:
return 0
if len(nums) == 1:
return nums[0]
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
return dp[-1]
做DP题最容易踩的坑是“状态定义不清晰”。比如这道题,如果把
dp[i]
错误定义为“第i个房子必偷的最大值”,那转移方程就要变,边界条件也要变,很容易写错。我的建议是动手写代码前,先把状态定义写在纸上,把转移方程写清楚,再动键盘。
Hot 100里值得反复做的DP题还有“最长递增子序列”“编辑距离”“零钱兑换”。尤其是“编辑距离”,几乎是DP状态定义和转移的集大成者,一旦吃透,你对二维DP的掌握会上一个台阶。
5. 刷题过程中的高频问题与排查技巧
5.1 常见问题速查表
我把自己刷题过程中踩过的坑、以及和周围朋友交流时大家常遇到的问题整理成了下面这张速查表:
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 看题解能看懂,自己写就卡壳 | 缺少主动输出练习 | 看完题解后关掉答案,当场默写代码,第二天再复现一次 |
| 老在边界条件翻车 | 没有考虑空输入、单元素、数值溢出 | 写完代码逐行走一遍边界用例,养成习惯 |
| 暴力解法能过,但超时 | 没有识别单调性或者重复计算 | 想想能不能用二分、前缀和、哈希表、双指针优化 |
| 树形题递归写不清楚 | 递归出口和单层逻辑混在一起 | 固定套路:先写终止条件,再写当前层做什么,最后递归调用 |
| DP题状态定义总是想歪 | 没有先做问题拆解 | 先画表格手动填一遍状态,再总结转移规律 |
| 刷了50题还是没感觉 | 刷题顺序太散、没有归类 | 换成分组刷题法,先按算法类型集中训练 |
| 遇到Hard题直接放弃 | 把Hard题看得太重 | Hot 100里的Hard题大多只是Medium的进阶,先尝试用Medium模板解 |
| 做题速度太慢 | 写代码前没有想清楚 | 强制自己在白纸上写出思路和伪代码再动笔编码 |
这张表我可以说是用大量时间踩出来的。很多人以为“刷题就是一直做新题”,但实际上“复盘错题”比“刷新题”重要得多。分享一个非常实用的技巧:把每道Hot 100题用一句话记下解题思路,做成一个表格,比如“题目15:三数之和——排序后固定一个数,剩下两个数用双指针”。每天早上花10分钟过一遍这个表格,复习效率非常高。
5.2 看题解的正确姿势
“hot100题解pdf”几乎人手一份,但很多人看题解的方式是错的。最常见的问题:先看题解再做题,看完觉得自己会了,实际上根本没学会。
我认为题解的正确打开方式是这样的:
- 第一优先级是独立思考。哪怕15分钟没有任何结果,这15分钟的思考也有价值,因为你在脑子里建立了自己的解题路径,即使走不通,后面看题解时也能对比出“我的思路和标准思路差在哪里”。
- 看题解时重点看思路,而不是代码。先用文字理解“为什么这么做”,能用自己的话复述一遍,再动手写代码。如果直接看代码,你只是在做翻译工作,把题解代码抄一遍,很难形成自己的理解。
- 看完题解后要做“变式练习”。比如看懂了“三数之和”,可以试着自己做“四数之和”,看看双指针思路能不能迁移;看懂了“爱吃香蕉的狒狒”,可以去找同类二分答案题练手。
好的题解往往会在评论区被大量讨论,LeetCode官方题解和最高赞题解结合起来看最佳,一个给规范结论,一个给直觉理解。
5.3 时间管理的实操建议
很多读者会问:一边上班/上课一边刷Hot 100,需要多长时间?这个问题没有标准答案,但我的经验可以给你参考。
如果是零基础,每天保证1小时,周末多投入1小时,大约6到8周能比较扎实地完成第一轮。如果是学过数据结构但很久没刷,每天2小时,可以压缩到3到4周。第一轮不要贪多,刷完一道题就总结一道题,做到“做一道题,会一类题”。
具体到每天怎么安排,我建议把时间拆成“做题前10分钟复习昨天的题”和“做题过程中记录卡点”。你不需要一次性把整道题写完再休息,可以先想思路、写伪代码,再在一段时间内专注编码。LeetCode自身的每日一题和周赛也可以用起来,作为对Hot 100的有益补充。
这里还要说一个容易被忽视的点:不要连续几天只刷题不做任何总结。没有总结的刷题,数量和水平是不成正比的。我见过很多人半年刷了300多题,但一问到“某类题的核心思路”还是讲不清楚,这就是典型的“刷题而不思考”。与其追求数量,不如把每道题吃透。
写在最后的小技巧
Hot 100刷到最后,我自己最大的体会是:这份题单真正锻炼的不是记忆,而是“识别题目模式”的能力。当你刷到后面,看到一道新题,脑子里会自动跳出“这不就是反转链表的变体吗”“这是二分答案”“这是状态压缩DP”,这时候你就已经跨越了新手阶段。
最后再分享一个一直被低估的技巧:用费曼学习法刷题,找个朋友或者对着空气把思路讲一遍。你会发现能讲明白的题才是真会的题,讲不清楚的地方就是你的盲区。把Hot 100当作战场地图,一步一步推进,后面再做其他题库或者参加周赛,整个人的状态是完全不一样的。
更多推荐


所有评论(0)