ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LeetCode Top 100刷题指南:从动态规划到BFS的算法面试突破

LeetCode Top 100刷题指南:从动态规划到BFS的算法面试突破 如果你正在准备算法面试,大概率听过“LeetCode Top 100”这个说法。市面上的题集、公司面经、培训课程都在反复提这100道题,好像刷完它就能拿到心仪offer。但真正动手刷过的人会慢慢发现,问题根本不是“刷完”这么简单——有人刷了三遍还是记不住思路,有人刷到一半就卡死在动态规划上,还有人刷完了面试照样挂。所以我想结合自己刷题、带新人、做模拟面试的经历,把“LeetCode Top 100道算法题”这件事拆开揉碎讲一讲:它到底是什么、该怎么刷、刷到什么程度才算有效,以及最常见的坑在哪里。这篇文章不打算给你列一份干巴巴的题目清单,而是会讲清楚每类题型背后的核心逻辑,也会顺便提到几个高频热词里出现过的具体题目,比如“腐烂的橘子”“爱吃香蕉的狒狒”这类偏实操的题,帮你把刷题路线走得更顺。1. 为什么是Top 100:从题海战术到精准打击1.1 Top 100不是选择题,而是重点题先纠正一个误区:LeetCode Top 100并不是“最简单的100道”,也不是“随机挑的100道”。它是从LeetCode上千道题库里,根据面试出现频率、题目质量、考点覆盖度综合筛选出来的一个集合。换句话说,这100道题代表了算法面试中最常被问到的原型题,很多实际面试题不过是这些原题的变形。我见过不少人一上来就刷LeetCode的easy题,刷了200道以为自己很勤奋,结果一面试遇到medium就懵。为什么?因为easy题之间缺乏梯度,很多easy题只是考察某个API调用或者最基本的遍历,根本起不到训练算法思维的作用。而Top 100里虽然也有easy,但更多是那种“看着容易,做起来才知道深”的题,比如两数之和、反转链表,看起来简单,但考察的是对哈希表、指针操作、边界条件的理解是否扎实。所以我的观点是:Top 100更像是一份重点题目精讲提纲,而不是一本习题集。它的价值在于帮你用有限的精力覆盖最高频的考点,而不是让你陷入题海无法自拔。1.2 这100道题背后的考点分布如果把Top 100按数据结构与算法分类,大致会落在几个固定领域:数组与字符串、链表、栈与队列、树与二叉树、图与搜索、动态规划、贪心、二分查找、哈希表。其中动态规划占比相当高,大概在20道左右。其次是二叉树和链表,加起来也有20道上下。数组类题目最多,因为它是很多算法的容器。图与搜索虽然数量不算最多,但只要出现,往往就是medium或hard,比如热词里提到的“994腐烂的橘子”就是典型的BFS题目。理解了这些分布你就明白,刷Top 100不是平均用力,而是要按考频排序,先把数组、链表、树、DP这四大块吃透,再去看图、二分、贪心。我个人的习惯是先把考频最高的三类(数组、链表、树)刷完,心里就有底了,因为这三类题目的技巧是互通的,比如双指针既可以用在数组上,也可以用在链表上;递归既是树的遍历方式,也是链表反转的一种解法。1.3 适合人群与前置基础Top 100适合谁?我觉得适合三类人:一是准备校招或跳槽、时间有限的人,刷全题库不现实,重点突破这个集合性价比最高;二是已经刷过几十道题但思路混乱、不成体系的人,需要通过高频题把知识网络串起来;三是非科班转码的人,基础薄弱但目标明确,靠Top 100快速建立算法直觉。但我不建议完全零基础的人直接上手。如果你连“什么是时间复杂度”“栈和队列的区别”都不清楚,建议先用一周时间补一下数据结构基础,再开始刷题。这不是劝退,而是经验之谈——没有基础直接刷题,很容易被打击到怀疑人生。2. 刷题前的三个准备:语言、环境与复盘机制2.1 语言选型:Python、Java还是C,我为什么选Python选哪门语言刷题,直接影响你的刷题效率。我个人用的是Python,因为它代码量少,调优成本低,让你更专注算法本身。同样是反转链表,C可能要写十几行,Python几句就搞定了。而且Python的列表、字典(哈希表)极其好用,很多题目用Python写起来就像是在描述思路而不是在写代码。当然,Java和C也有优势。Java的强类型和工程化习惯能让你更注意边界条件,适合大厂后端面试;CPP更贴近底层,很多大厂基础架构岗会偏爱C。但如果你不是有特别的目标,我建议选Python,先把刷题这件事跑通,后续真要换语言,算法思路是通用的,只需要花时间熟悉语法。一个细节是,你需要熟悉这门语言的常用API。比如Python里的collections.deque用于BFS,heapq用于堆操作,functools.lru_cache用于记忆化搜索。这些API在Top 100里经常用到,如果到了面试才临时查,心态会崩。2.2 高效刷题环境:本地调试与在线编辑器的配合LeetCode自带的在线编辑器其实已经够用了,但遇到复杂题目时,还是建议在本地跑一遍完整测试。我的做法是:在本机装一个Python环境,写一个测试脚本,把LeetCode的示例用例和自定义的边界用例都塞进去跑。这样能看到打印日志,比在线编辑器一点点调试要快得多。这里分享一个工具搭配:VS Code加Python插件,或者直接用PyCharm的社区版。本地调试时,善用print日志输出关键中间变量,比断点更直观。对于链表、树这类结构,建议自己写一个打印函数,比如把链表转成列表、把树层序遍历出来,这样能快速验证结果是否正确。另外,我强烈建议你建一个“代码模板库”。把常用的算法模板存下来,比如二分查找模板、BFS模板、DP状态转移模板,每次刷题先从模板出发,再按题目要求修改。这样既能加快速度,也能降低思维负担。2.3 建立自己的刷题记录表很多人刷题是“刷一道忘一道”,原因就是没有复盘机制。我建议你用一张表格(Excel、Notion、或者GitHub上的README都行)记录每道题的状态,至少包含以下几列:题目编号与名称分类(数组、DP、树等)难度首次提交是否通过核心思路(用自己的话写,不要抄题解)是否做了一题多解需要二刷还是三刷以我自己的经验,一张合格的刷题表能帮你节省大量复习时间。每周固定抽一天,把表里标记“需要二刷”的题目重新做一遍,你会发现第二次做的时候,很多思路自然就通了。这比盲目刷新题有意义得多。3. Top 100中的高频题型拆解:从暴力解到最优解3.1 数组与双指针:看似简单,其实变化最多数组类题目是Top 100的基石,很多看似是其他类型的题,最终都能归约到数组处理上。数组题最常用的技巧就是双指针,一个往左走,一个往右走,或者一个快一个慢。典型比如“两数之和”的排序版本,可以用左右指针逼近目标值;“盛最多水的容器”也是靠双指针缩小搜索空间。用双指针的核心思想是:通过指针移动来排除不必要的比较。每次移动指针时,要想清楚为什么可以移动它,而不是盲目地试。比如“三数之和”,排序后用一层循环加双指针,时间复杂度从O(n^3)降到O(n^2),这就是双指针最大的价值。数组题的另一个重点是区间合并和求最大最小值。比如热词里提到的“数组求区间最大值的算法题”,这类问题经常用到单调栈或前缀和。Top 100里不一定直接出原题,但变形题很多。所以刷数组题时,不要只满足于AC(通过),要思考一下“如果有重复元素怎么办”“如果数组有序怎么办”“如果数据量特别大怎么办”。一个实用技巧是,拿到数组题先看是否有序。如果数组有序,你就能用二分查找、双指针这些技巧;如果无序,可能就需要哈希表记录出现过的值。3.2 链表题:多练几遍,直到能默写链表在Top 100里的比例不小,而且几乎每道题都在考察同一个核心能力——指针操作。链表的难点不在算法,而在“别指丢了”。经典的“反转链表”就有迭代和递归两种写法,迭代需要三个指针(cur、prev、next)一直转,递归则需要理解函数调用栈。链表题目的高频考点包括:反转链表、合并两个有序链表、删除倒数第N个节点、寻找链表中点、环形链表检测。这些题一旦掌握了,其实是比较机械的操作。我建议把链表常见操作写到滚瓜烂熟,最好能不看代码默写出来。因为面试时,链表题往往是热身题,你答得利索,会给后续答题留下好印象。链表题的一些细节值得注意:是否需要dummy节点?递归的终止条件是什么?边界条件包括空链表、只有一个节点的链表,这些都要单独想清楚。尤其是dummy节点,在删除头节点时特别有用,可以省去对头节点的特殊判断。如果你觉得链表题容易出错,可以试试在纸上画一下指针指向的过程。画完再写代码,出错率会低很多。3.3 动态规划题:Top100里真正的分水岭动态规划是Top100里区分度最高的题型,也是很多人刷到中途放弃的原因。DP题不只是背状态转移方程,关键是要理解“装满容量为j的背包有几种方法”这类问题的抽象过程。Top100里的DP题大致分为几类:简单一维DP(如爬楼梯)、二维DP(如不同路径)、背包问题变形、区间DP、状态机DP。我的经验是,遇到DP题先不要急着写代码,按下面四个步骤走一遍:定义状态:dp[i]或者dp[i][j]代表什么?转移方程:当前状态能从哪些状态转移过来?初始化:dp[0]或dp[0][0]怎么定?遍历顺序:一维是从左到右?二维是从上到下?以热词里提到的“爱吃香蕉的狒狒”(原题是LeetCode 875, Koko Eating Bananas)为例,它其实是二分查找不是DP,但这类“最小值、最大值、满足条件的最优解”问题,往往是二分和DP的结合体。刷DP题时,要注意和一题多解结合起来。DP题最适合用记忆化搜索来做铺垫。先写递归的暴力解法,加上缓存(lru_cache或手动memo),把它改成自顶向下的DP,然后再改写成自底向上的递推。这个过程让你理解递归和DP的关系,而不是背模板。前期可以多用记忆化,等熟悉了再尝试纯递推。3.4 图与搜索:从“腐烂的橘子”到BFS模板图相关的题目在Top100里数量不算最多,但一旦出现,往往都是看起来很吓人的medium或hard。比如热词里提到的“994腐烂的橘子”,本质上是一个BFS求最短时间的问题。这类题其实有固定解法——把初始所有腐烂橘子当成BFS的第一层,然后一层层向外扩散,记录扩散了几层,就是需要的分钟数。BFS的标准模板是队列加visited集合。第一步把初始节点全部入队,第二步从队首弹出节点,处理它周围的邻居,如果邻居满足条件且未被访问,就入队并标记。这个模板能解决一大片题目,包括岛屿数量、二叉树的最小深度、单词接龙等。DFS也同样重要,特别适合解决“求所有路径”的问题。Top100里有“岛屿数量”这种DFS题,也有“全排列”这种回溯题,回溯的本质也是DFS加状态恢复。我建议把DFS、BFS、回溯三种模板分开归纳,记清楚它们各自的适用场景。以“腐烂的橘子”为例,核心是怎么处理多源BFS。多源BFS其实很简单,把所有起点先入队,然后按层扩散,最后判断还有没有新鲜橘子。如果还有,就返回-1。这类题在面试中考察得很多,因为图论并不是所有人都精通,能写出清晰的BFS已经能超过很多人了。4. 我建议的Top 100必刷顺序与题单4.1 第一阶段:热身与基础(1-20题)这个阶段不用追求刷难题,先从数组、哈希表、链表这些基础题入手。推荐先做“两数之和”“反转链表”“合并两个有序链表”“有效的括号”“最长公共前缀”这类题。目标是恢复手感,熟悉在线评测环境,并练习怎么用本地调试。这个阶段每天刷两三道就行,但每道题都要保证吃透。所谓吃透,不是看了题解敲一遍代码就叫会了,而是能不看题解,自己从零推导出思路,并能用面试的口吻讲一遍。对于基础题,我还会在一周后再做一次,检查是否真的记住了。4.2 第二阶段:核心算法突破(21-60题)第二阶段进入树、动态规划、二分查找、滑动窗口这些核心考点。这个阶段会遇到一些经典题目,比如“二叉树的遍历”“最长回文子串”“盛最多水的容器”“跳跃游戏”等。重点说一下树题。树的题目几乎都可以用递归解决,所以要先搞清楚递归的终止条件。前序、中序、后序、层序都需要手写一遍,尤其是层序,要用到队列。遇到“二叉树的最大深度”“验证二叉搜索树”这类题,一定要熟练掌握。动态规划也是这个阶段的主旋律。先从一维DP开始,比如“爬楼梯”“打家劫舍”,再过渡到二维DP和背包问题。这个阶段要接受自己一开始想不出来状态转移方程,这是正常的。哪怕看了题解,也要把每道题重新在草稿纸上推一遍,写清楚dp数组的含义和转移过程。4.3 第三阶段:难题挑战与思维提升(61-100题)第三阶段开始出现hard题和图论题,比如“腐烂的橘子”“爱吃香蕉的狒狒”(其实是medium)还有一些思维量很大的题。这个阶段的核心目标不是把每道题都AC,而是培养“看到题目就能分类”的能力:这题是DP还是贪心?是图搜索还是字符串匹配?一旦分类对了,解法框架就有了。遇到hard题卡住是很正常的,哪怕是大厂面试官,看到hard题也会先皱眉。我的建议是,一道hard题给自己45分钟到1小时的真实思考时间,如果还是没思路,再去看题解。看题解不要只看代码,重点看别人的思考过程。比如他是怎么想到用单调栈的,他是怎么定义状态的。看完题解后,合上书自己重新写一遍,写不出来就再看一遍,直到能独立AC。这个阶段还要开始做“一题多解”练习。比如“两数之和”可以用哈希表,也可以用排序加双指针;“最长上升子序列”可以用DP,也可以用二分加贪心。多解的意义在于拓宽思维,面试时如果面试官要求优化,你能随时切换。5. 刷题过程中最容易踩的四个坑5.1 看题解秒懂,合上书就忘这是最常见的问题,每个人刷题都会遇到。解决办法只有一个:主动回忆。看完题解后,不要立刻敲代码,而是合上书,在草稿纸上把思路画出来,再自己写代码。如果写不出来,说明你没有真理解。我会准备一个“刷题笔记本”,每道题记录题号、解法、为什么这样想、是否踩坑。下次复习时,只打开笔记本回忆,不看代码。这个过程比刷十道新题还有用。5.2 边界条件:空输入、极端值的恐惧边界条件之所以是坑,是因为它们只会在你出错时刷存在感。很多题在LeetCode上提交后经常出现“数组越界”“死循环”“空指针”这类的报错,基本就是边界没处理好。我建议每次写完代码,先检查以下边界:数组的长度是0或1的情况数组是递增或递减的情况链表为空或只有一个节点的情况树为空或只有根节点的情况目标值比所有元素都大或都小的情况对于二分查找这类操作,边界尤其重要。比如while (left right)还是while (left right),直接决定代码是否正确。这种情况建议背熟一种固定的二分模板,不要每次临时想。5.3 只求通过,不求复杂度很多人刷题有一个坏习惯:只要AC就满足了,根本不看时间复杂度和空间复杂度。这样刷再多题,遇到数据量大的场景还是会挂。比如“两数之和”暴力解法也能过,但时间复杂度是O(n^2),面试官肯定会问你能不能优化到O(n)。我刷题时会强迫自己分析复杂度的两种写法:一种是暴力解,先写出来拿分;另一种是优化解,想清楚为什么能用哈希表或双指针降低复杂度。面试时,通常面试官会先让你说思路,再看你写代码,最后问复杂度。如果你养成这个习惯,回答会非常顺手。5.4 刷题与面试脱节最后一个坑是把刷题当成背题。LeetCode上直接出原题的概率越来越低,更多是考变形题。比如Top100里的“合并两个有序数组”,面试时可能会变成“合并K个有序链表”。你如果只是背住了原题的代码,遇到变体就会不知所措。解决办法是刷题时多问自己“这个解法依赖了哪些性质?”如果数组有序,所以才能用双指针;如果链表合并,可以用分治法。把每个解法的适用条件总结出来,遇到变体才能迁移。6. 把刷题成果转化为面试能力6.1 从记忆答案到讲题思路真正面试时,代码写得好不好固然重要,但更重要的是你能不能把自己的思路讲清楚。我建议从刷第10道题开始,就尝试用“讲题模式”来练习:拿到题目,先说出你的思路、复杂度,然后写代码,最后再解释一遍为什么这么做。这个方法也能让刷题不再枯燥,因为你是在培养一种输出能力,而不是机械输入。特别是同伴之间互相讲题,进步速度非常快。我经常在社区里看别人写题解,然后就用自己的话复述一遍。你会发现,能讲明白的题,才是真的会了。6.2 一题多解与复杂度分析习惯面试评分标准通常包括正确性、复杂度、代码风格和沟通能力。一题多解最大的好处,是让你能根据面试官给的限制条件灵活调整方案。比如空间不够时改用双指针,时间不够时用哈希表。提前储备多种解法,面试时才能保持从容。复杂度分析也是必考项。每次写完代码,快速说出时间复杂度,并且解释为什么是这个复杂度。比如“每个元素最多被访问两次,所以时间复杂度是O(n),额外空间是O(1)”。这样让自己养成分析的习惯,出错率也会下降。6.3 坚持复盘的个人经验最后分享一点个人体会:刷题不可能一蹴而就,哪怕Top100刷完,过一个月不复习也会忘。我会把刷题记录表升级成一份自己的“算法索引”,按类型记录每个模板的代码和适用条件。每当面试前或换工作时,就翻一遍索引,把高频题重新做一遍。另外,遇到一道好题,不要满足于一遍AC,我会在两周后再做第二遍,用记事本记录下来哪个知识点还模糊,然后针对性补强。我自己就是在第三遍刷“腐烂的橘子”时,才彻底理解了多源BFS的边界处理。这种反复带来的熟稔感,真的会让人在面试时底气十足。每个人的记忆曲线不同,但复盘节奏一致:刷完一遍不算完,至少二刷错题,三刷典型题。如果你能把Top100按这个节奏吃透,那么无论面试题怎么变形,你都能在这个框架内找到解法入口。
返回列表