尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

LeetCode刷题指南:模式识别、经典题解与高效路线

发布时间:2026/9/24 23:56:05

资讯中心
01
ARTICLE

LeetCode刷题指南:模式识别、经典题解与高效路线

LeetCode刷题指南:模式识别、经典题解与高效路线
在社区里经常看到两类人一类是刚注册 LeetCode打开题库却不知道从哪里下手收藏了一堆刷题路线帖结果还是没坚持下来另一类是已经刷了三百多题但面试时题目稍微拐个弯就卡壳甚至开始怀疑自己是不是在无效刷题。这两种状态我都经历过。作为一个从周赛签到打到现在每周必刷的老选手我最大的感受是刷题不是拼题量而是拼模式识别的能力。很多人把 LeetCode 当作题库刷一道忘一道本质上是因为没有把题目背后的套路提炼出来。这篇内容我围绕 LeetCode 刷题指南、热门100题、简单题价值、几道经典题解994 腐烂的橘子、073 爱吃香蕉的狒狒、链表相关以及周赛430的观察一次性整理出我这几年真正在用的方法论和实战拆解希望能帮你少走点弯路。1. 刷题前先想清楚LeetCode 到底在考什么1.1 题目背后是问题建模能力LeetCode 表面上是数据结构与算法的题库内核其实是在考察两件事第一能不能把一个现实问题抽象成已知的算法模型第二能不能在抽象之后用代码把边界情况和复杂度控制好。很多人以为刷题是在学算法其实更像是在训练问题建模。比如看到求最短路径要立刻想到 BFS 或 Dijkstra看到最大值最小要想到二分答案看到子串匹配要想到滑动窗口、前缀和或者 KMP。这些映射关系越熟练读题到动手写代码的时间就越短。面试官不关心你背了多少题他关心的是你拿到一个从没见过的场景时能不能快速拆解。这个拆解能力不是靠背诵来的是靠反复接触不同题型、总结共性来的。这也是为什么有些刷了上千题的人反而不如只刷了一两百题但每道都深度复盘的人——前者把题当任务后者把题当样本。1.2 刷题的本质是模式识别我刷题的早期阶段有一个很明显的误区喜欢按题号顺序刷从 1 开始一路往下。后来发现真的记不住刷到 100 题的时候1 题的解法已经模糊了。后来我换了个思路按知识点打标签链表一类的放一起BFS 一类的放一起背包问题的动态规划放一起。这样做的效果立竿见影因为我开始看到题目之间的骨架相似。比如二叉树的层序遍历、腐烂橘子的扩散、单词接龙、打开转盘锁这几道题看起来毫无关系但它们的代码框架几乎一样先初始化队列把起点入队然后一层一层往外扩展每一层对应一个时间单位或者距离单位。一旦你在脑海中形成这种模式卡新题就不是新题了它只是旧模式换了一层外衣。这也是题解真正有用的地方——不是抄代码而是看别人是怎么把题目归类到某个模式里的。1.3 别被题量绑架我经常在社区里看到有人打卡今天第 500 题。说实话这个数字现在很难吓到我了我更在意的是这个人能不能在白板上把一道经典题讲清楚。LeetCode 题库接近三千题人不可能全部刷完也不需要。明确告诉你把高频考点覆盖到位三百题足以应对绝大多数面试场景。关键是怎么定义覆盖到位每个核心知识点至少做过 10 到 20 道题而且至少有 5 道是不看题解也能写出来的程度。如果只追求数量刷完之后给你一道中等难度的区间合并题你可能还是懵。刷题本质是刻意练习不是流水线计件。宁可一周只精刷 7 道题也不要一天囫囵吞枣过 30 道。2. 从腐烂的橘子拆解 BFS 类题目的通用解法2.1 题目描述与核心考点LeetCode 994 腐烂的橘子是 BFS 专题里非常经典的一道题也是搜索热词里的常客。题目给一个 m x n 的网格每个格子的值有三种0 代表空格1 代表新鲜橘子2 代表腐烂橘子。每分钟腐烂橘子会把它上下左右四个方向相邻的新鲜橘子也变腐烂。要求计算直到网格里不再有新鲜橘子最少需要经过多少分钟如果始终有新鲜橘子无法被污染返回 -1。这道题的考点非常明确多源 BFS。常规 BFS 是从一个起点开始扩散但这里初始状态下可能同时存在多个腐烂橘子而且它们是在同一分钟开始扩散的。如果对每个腐烂橘子分别做一次 BFS再把时间求交逻辑会很别扭性能也不好。正确做法是把所有初始腐烂橘子一起入队把它们当作同一个扩散源的多个起点同步向外扩展。2.2 为什么是 BFS 而不是 DFS很多人第一反应是 DFS 递归因为感染邻居听起来像遍历。但 DFS 是沿着一条路走到底再回头而腐烂扩散是每一分钟所有边界同时向外推进一层这正好是 BFS 的层序遍历特征。你可以把每一分钟理解成 BFS 中的每一层第 0 层的腐烂橘子在一分钟后生成第 1 层的腐烂橘子第 1 层再在一分钟后生成第 2 层。层数就是分钟数。如果强行用 DFS你需要额外维护每个橘子被感染的最短时间并反复比较代码复杂度瞬间上升而且递归深度在网格很大时还有爆栈风险。所以 BFS 是这题唯一合理的解法。2.3 多源 BFS 的代码骨架下面这份代码是这类题的标准模板不只在腐烂橘子在很多多起点扩散题里都能直接套from collections import deque def orangesRotting(grid): m, n len(grid), len(grid[0]) q deque() fresh 0 for i in range(m): for j in range(n): if grid[i][j] 2: q.append((i, j)) elif grid[i][j] 1: fresh 1 if fresh 0: return 0 directions [(1, 0), (-1, 0), (0, 1), (0, -1)] minutes 0 while q and fresh 0: minutes 1 for _ in range(len(q)): x, y q.popleft() for dx, dy in directions: nx, ny x dx, y dy if 0 nx m and 0 ny n and grid[nx][ny] 1: grid[nx][ny] 2 fresh - 1 q.append((nx, ny)) return minutes if fresh 0 else -1有几个细节值得强调。第一个是层数统计的写法在 while 循环里先minutes 1然后用for _ in range(len(q))把当前队列里的所有节点处理完这就是这一分钟扩散的所有边界。如果不加这层 forBFS 会退化成逐节点处理时间统计就会错乱。第二个细节是fresh计数。我在初始遍历时数了有多少个新鲜橘子每感染一个就减一最后判断是否归零。这个设计避免了遍历整个网格来判断是否还有新鲜橘子把额外的时间复杂度省掉了。很多新手喜欢在处理完队列之后重新遍历数组这里就是个明显的性能浪费。2.4 这类题的变体与易错点腐烂橘子并不是特例。单词接龙里每个单词是一个节点每次改一个字母走一步本质上就是单源 BFS打开转盘锁里每个密码组合是节点拨动一次就是一个方向也是 BFS地图上多个着火点同时蔓延的问题和腐烂橘子完全同构。把模板背熟之后大部分最短时间最少步数的题都能套。易错点主要集中在这几处忘记处理初始就没有新鲜橘子的情况。这时候答案应该是 0 而不是 -1很多人在这一步栽过。队列初始化的位置不对。多源 BFS 必须先把所有起点入队不能在循环里边遍历边入队否则会破坏同一时刻扩散的语义。层数统计放在 for 循环内部。这样会把一个节点算成一层分钟数就变成了节点数。边界检查漏写。0 nx m and 0 ny n不能少否则数组越界。如果你想验证自己有没有真正掌握可以把输入换成二维字符矩阵或者把四方向换成八方向再或者要求输出每个新鲜橘子被感染的时间矩阵这些都是同一个模板的小改版能写出来就说明理解了。3. 爱吃香蕉的狒狒二分答案如何降低思维门槛3.1 题意转化与暴力思路LeetCode 073 爱吃香蕉的狒狒也是一道被高频搜索的题。题目说狒狒吃香蕉有若干堆香蕉每堆根数不同狒狒每小时可以选择一堆最多吃 K 根如果这一堆少于 K 根它就把这堆吃完这一小时内不会再吃其他堆。要求它在 H 小时内吃完所有香蕉问最小的 K 是多少。第一次看这道题最容易想到的暴力解法是从 K 1 开始试一直试到某一堆的最大根数找到第一个能在 H 小时内吃完的 K 就是答案。这个思路正确但复杂度是 O(max(piles) * n)如果香蕉堆里的最大数量是 10^9这个循环是绝对跑不完的。关键洞察在于K 越大吃得越快完成时间越短K 越小吃得越慢完成时间越长。也就是说存在一个临界点 K0使得所有大于等于 K0 的 K 都能在 H 小时内完成所有小于 K0 的 K 都不能完成。这是一个典型的单调函数而在一个单调区间里找边界正是二分查找最擅长的场景。3.2 二分答案的代码实现我们二分的东西不是数组下标而是每小时吃多少根这个答案本身。这和传统二分查找有区别但本质相同。直接看代码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是上取整的写法。比如一堆有 10 根每小时吃 3 根那么需要 4 小时而不是 3 小时因为 10 / 3 3.33向上取整为 4。这是本类题最容易写错的地方很多人下意识用p // k结果要么低估时间要么多减一答案就会偏小。二分查找的边界也很有讲究。这里用的是left right配合right mid和left mid 1。这个组合适用于找到最小的满足条件的值。如果写成while left right搭配return left很容易死循环或者越界。记住这个固定的观感求最小可行值时right mid收缩右边界left mid 1排除不可能区间。3.3 识别这类题的特征我后来发现类似爱吃香蕉的狒狒的题非常多它们往往不直接告诉你用二分但有几个明显的语言特征出现最大和最小同时出现。比如使所有船只承运的最大重量最小化每个学生分到的最大书本数最小化。某个操作结果随参数的增大呈单调变化。比如吃香蕉速度越快时间越短船载重量越大运输天数越少。答案是一个连续的整数范围暴力枚举可行但太慢。这类题最常见的变体是 LeetCode 1011 在 D 天内送达包裹的能力、LeetCode 410 分割数组的最大值。它们的代码骨架几乎一样只把can_finish里的逻辑稍微改一下。如果你能把爱吃香蕉的狒狒彻底吃透这分数基本上就拿到手了。3.4 边界条件与常见坑实际写代码时有几个边界容易出问题H 小于堆数的情况。如果每小时最多吃一堆那么至少需要 piles.length 小时当 H 小于这个数直接不可能。但 LeetCode 原题保证 H piles.length所以不需要特判但面试时最好主动提一下。left 的初始值。有人习惯从 0 开始这会导致 can_finish(0) 出现除零错误。从 1 开始最安全因为每小时吃 0 根没有意义。max(piles) 作为 right 的合理性。K 等于最大堆的根数时每一堆最多一小时就能吃完总耗时不超过堆的数量一定满足 H 的约束所以它是一个可行上界选它不会漏解。踩过这些坑之后我对二分的理解深了一层二分不是只能用在排序数组里一切具有单调性的问题都可以尝试用二分去逼近答案。这是刷 LeetCode 一个很大的思维飞跃点。4. 链表题指针操作的边界感从哪来4.1 链表在面试中的地位链表是 LeetCode 题库里非常高频的一类热门100题里就有反转链表、环形链表、合并两个有序链表、删除链表的倒数第 N 个节点、两数相加等等。链表实现不难但极其容易写出边界 bug所以面试官爱用因为这个考点考察的是你能否把指针的时序逻辑理清楚。链表题的核心难点就一个指针操作一旦改变了节点之间的引用关系就可能会导致节点丢失、指向错误、循环引用等连锁问题。解决这个问题的通用手段是画图。我知道这话听起来像老师上课唠叨但真的管用。遇到稍微复杂一点的链表题比如 K 个一组反转链表不画图纯靠脑补几乎必错。4.2 虚拟头节点和快慢指针链表题里有几个通用技巧。第一个是虚拟头节点dummy node。当你要删除头节点或者需要构造新链表时用一个 dummy ListNode(0, head) 来统一操作可以省掉大量判断头节点为空的特殊逻辑。第二个是快慢指针。判环用 fast 走两步、slow 走一步找中点也是 fast 走两步、slow 走一步找倒数第 N 个节点可以让 fast 先走 N 步再快慢一起走。以反转链表为例这是链表最基础的题代码可以短到几行但每根指针的含义必须非常清楚def reverseList(head): prev None curr head while curr: nxt curr.next # 先保存后继节点 curr.next prev # 当前节点指向前驱 prev curr # 前驱移动到当前 curr nxt # 当前移动到后继 return prev这里的核心是先nxt curr.next如果不保存这一步改了curr.next之后你就永远找不到原来的下一个节点了。这个顺序问题在反转整个链表时还好一旦变成反转区间或K 个一组反转多个指针同时移动时保存后继的顺序就更需要小心。4.3 边界条件的三张检查表链表题的边界条件很典型我习惯在写完代码后按三张表逐一检查第一为空和长度为 1 的链表代码能否直接返回正确结果。很多 bug 都是因为没有考虑head is None。第二操作位置在头部和尾部时是否和中间位置逻辑一致。删除头节点时如果没有 dummy node就要单独写一段分支。用 dummy node 可以把这些分支统一掉。第三循环跳出的条件。比如判环代码def hasCycle(head): slow fast head while fast and fast.next: slow slow.next fast fast.next.next if slow fast: return True return False这里while fast and fast.next两个条件缺一不可。如果只写while fast那么fast.next.next可能因为 fast.next 为空而报属性错误。如果只写while fast.next对于空链表就直接异常了。这类细节没有捷径只能靠多写多错来建立条件反射。4.4 调试链表题的经验链表题在本地调试比数组麻烦我后来养成了一个习惯在工具函数里单独写一个打印链表的辅助函数把每个节点的值按顺序列出来。每次改完节点指针立刻打印一遍观察节点顺序是否符合预期。这个做法在调试链表排序链表反转区间时特别有效。另外一个经验是复杂度分析不要只看时间链表题的空间复杂度经常被忽视。比如合并两个有序链表的递归写法空间复杂度是 O(mn)因为递归栈深度和链表长度相关。面试时如果你能指出迭代写法可以把空间降到 O(1)这会是一个明显的加分项。链表题比拼的从来不只是能不能解开还有能不能在约束下写出更好的解法。5. 周赛、热门100题与刷题路线如何搭配5.1 周赛430带来的信号最近一期 LeetCode 周赛430结束之后我看了一下题目分布第一题是典型的简单题考的是数组基础操作不需要很复杂的数据结构第二题开始涉及一点贪心和模拟第三题是中等偏上的数据结构题第四题是综合性很强的困难题。这个分布其实一直很稳定周赛的定位就是用有限时间考察你面对陌生题目的现场拆解能力。很多选手参加周赛的心态是我要 AK 四道题我反而觉得没必要。周赛的核心价值在于定期提醒你你的模式识别速度够不够快代码的边界处理够不够稳。如果一场周赛下来你第一题就因为边界条件卡了 20 分钟那就说明基本功还有漏洞比刷十道简单题更有价值。我经常建议身边人把周赛当体检而不是比赛热身为主排名为辅。5.2 热门100题为什么值得反复刷LeetCode 热门100题Top 100 Liked Questions是社区里点赞和提交最活跃的一百道题覆盖了面试中最常见的高频考点。我第一次刷的时候只是顺着列表过了一遍后来发现效果一般。第二次我换了一个思路不看题号顺序按照知识点重新分组。比如把两数之和三数之和四数之和放一起你会看到双指针和哈希表在不同条件下的取舍把最大子数组和买卖股票的最佳时机打家劫舍放一起你会看到一维动态规划的基本套路把二叉树的中序遍历验证二叉搜索树二叉树的最近公共祖先放一起你会理解递归在树结构中的作用方式。这样刷过一轮之后再遇到热门100题覆盖范围外的新题不会觉得慌因为你脑子里的知识是成网的不是散点。热门100题也有自己的短板比如数学类题目相对偏少状态压缩动态规划也不多。所以它更适合作为主路线辅助以专题补齐。5.3 一套可落地的四阶段刷题路线结合这么多年的经验我给刚开始刷题的朋友一个比较稳的路线阶段一1到2周打基础。刷数组、哈希表、字符串、链表以简单题为主目标是掌握数据结构的基本操作。阶段二2到4周树和递归。刷二叉树遍历、递归回溯、二叉搜索树以中等题为主目标是把递归函数的状态传递想明白。阶段三1到2个月核心算法。刷 BFS/DFS、二分、贪心、动态规划中等题和困难题混合目标是建立看到题知道属于哪个算法的条件反射。阶段四持续进行用热门100题做总复习每周参加一场周赛检验状态把错题和卡顿点定期回头重刷。这个路线没有多玄妙但贵在阶段之间有明确的递进关系。很多人失败的原因是第一周直接冲动态规划困难题被打击到自我怀疑。刷题的节奏应该像跑步训练先能轻松跑五公里再考虑配速和间歇跑而不是第一天就尝试马拉松配速。5.4 关于题解的正确打开方式很多人做题遇到卡住就立刻点开题解然后抄一遍感觉自己会了。这种做法短期很爽长期几乎是负收益。正确的题解打开方式是给自己设一个挣扎时间比如 30 分钟到一小时这段时间可以查 API、画图、写注释但不能看题解。实在没有思路再去看题解但只看第一个关键提示不看完整代码然后自己往下写。看完题解之后还有一个重要的步骤归纳这道题的模式并记录在笔记里。我自己的笔记里每条记录都包括核心考点是什么、最优解的时间空间复杂度、我一开始卡在哪里、下次遇到什么特征可以联想到它。这个笔记才是我刷题真正积累下来的资产比 AC 数量有价值得多。6. 简单题不是水题被低估的训练价值6.1 简单题的错误打开方式不少刷题的人有一个偏见简单题太水不值得花时间直接上中等题和困难题。这个观点在面试准备阶段特别危险。我见过太多人连合并两个有序数组都写不利索却在刷困难题时自我感动。简单题真正的价值不在能不能做出来而在能不能用多种方法做出来并且讲清楚每种方法的 trade-off。以两数之和为例最简单的是暴力 O(n^2)好一点是哈希表 O(n)还有一种排序加双指针时间 O(n log n) 但空间可能 O(1)取决于排序是否原地。如果面试官问你如果数组是排好序的呢你得能立刻想到双指针从两端逼近。这三个进阶其实是一道简单题可以延伸出的完整知识链。6.2 一道简单题的多种解法训练模式识别很多简单题是模式种子。比如有效的括号是栈结构的最佳入口买卖股票的最佳时机是一维动态规划启蒙岛屿数量是图遍历启蒙。把简单题当切入点的意义在于你可以用最小的认知成本理解一个模板的完整结构然后到中等题里再验证、变形。我在刷腐烂的橘子之前先刷过二叉树的层序遍历所以对BFS 每一层对应一个时间单位已经有肌肉记忆。这就是简单题和中等题之间被隐藏的衔接关系。如果直接上腐烂橘子理解多源 BFS 就要多绕一个弯。从简单到中等的顺序本质上是在给你的模式识别系统搭脚手架。6.3 复盘才是刷题的核心资产无论简单题还是困难题真正决定成长速度的是复盘质量。我的复盘流程是这样的AC 之后先不急着下一道回到题目描述把为什么用这个算法再问一遍然后翻评论区找另一种解法的思路哪怕不写代码也要理解原理最后看一眼复杂度确认自己写的是最优解。隔一段时间重刷也很重要。我会把之前刷过的题标记上秒过有思路但卡壳完全不会三个等级。隔两周只重刷后两类。这个操作比刷新题更能检验真实水平因为刷新题你还可以归因于没见过而重刷熟悉的题如果还卡说明当初只是背下了代码没有内化思路。刷简单题的时候也要用同样的复盘标准。不要因为 AC 了就草草结束试着问自己如果我改变一个条件这个解法还能用吗如果数组长度扩大到十亿该怎么办这样的追问往往比刷十道新题更能锻炼一个人的算法思维。6.4 给不同阶段读者的一点个人体会根据我自己的经验刚开始学习数据结构和算法的朋友不要太焦虑。LeetCode 的题目量确实巨大但绝大多数题目都能归入有限的模式。你不需要做第一个写出困难题解法的人也不需要每次周赛都排名靠前你只需要保证自己比上周的状态好一点。把腐烂的橘子这类经典题吃透把爱吃香蕉的狒狒这类二分答案题练到条件反射把链表题的指针操作画图到熟练再配合一套适合自己的刷题路线和复盘节奏面试现场遇到新题时你至少不会慌。如果这篇文章能帮你少走一点弯路那它就很值了。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。