不用把LeetCode当成神坛上的东西它本质上就是一套题库和在线评测系统。但你要是追过热搜、逛过讨论区会发现围绕它的话题早就超出了刷题本身。LeetCode刷题指南、LeetCode简单题值不值得做、LeetCode热门100题到底该怎么用、周赛430打得稀碎怎么办这些才是一个普通程序员真正关心的东西。我刷了几年从一题都写不出来到稳定周赛三题中间踩过不少坑也总结了一些自己的方法。这篇东西不打算讲鸡汤也不打算堆概念就把我实际做题过程中的拆解思路、踩坑记录、以及一套可执行的刷题路线整理出来希望对正在纠结该从哪里下手的人有点用。1. 为什么说LeetCode刷题的核心不是刷而是建立题感很多人把刷题数量当成唯一指标好像刷到500题、1000题就自动变强了。但实际面试的时候遇到没见过的题照样卡住。这里的问题不在于刷得不够多而在于没有建立起题感。题感是个很玄的说法但可以拆成三个具体能力能识别这道题属于哪个解题套路、能判断最优解的方向、能在写代码之前大概估算出时间复杂度和边界条件。1.1 简单题的价值被严重低估了LeetCode简单题在很多人眼里是入门水平刷几道就跳过去了。但以我实际的经验来看简单题才是建立题感的基石。简单题的考点往往非常单一比如双指针、哈希表、基础遍历它不会像中等题那样把多个技巧揉在一起。正因为单一你才能清楚地看到什么特征对应什么解法。举个例子LeetCode热门前100题里很多简单题反复在考同一件事遍历数组时维护一个额外的数据结构。两数之和是哈希表、有效的括号是栈、合并两个有序链表是双指针。当你把这些简单题做熟你会形成一种条件反射看到查找是否出现过就想到哈希表看到括号匹配就想到栈看到有序数组就想到双指针或二分。这种条件反射就是题感的核心。它不是天生的而是通过刻意练习简单题建立的。1.2 热门100题为什么热门LeetCode热门100题不是官方钦定的而是由所有用户的提交行为自然形成的。它的特点有两个第一考点覆盖了面试最高频的算法类型比如链表操作、二叉树遍历、动态规划入门、BFS/DFS基础题第二这些题目的解法通常不止一种而且每种解法的思路都能迁移到其他题目上。我自己刷下来的感受是热门100题适合用来做专题训练的目录。按标签分类比如把所有链表题放一起刷把所有岛屿类DFS/BFS放一起刷把所有背包类DP放一起刷。你会发现同一种套路在不同题目里反复出现。比如BFS通常解决最短步数最少操作次数问题DFS通常解决是否可达路径是否存在问题。这个区分一旦建立起来遇到新题你至少能确定切入方向而不是对着空白的编辑器发呆。1.3 从看题解到写题解的转变刷题圈有个普遍的坏习惯就是五分钟没思路就点开题解看完觉得懂了然后下一题。这种状态持续很久只能感动自己。因为看懂题解和能写出题解是两码事前者是阅读后者是输出。我后来强迫自己做了两件事第一看完题解之后把代码关掉自己重新写一遍写不出来就再看再写直到能不依靠任何参考独立写出来第二把题解用文字写下来不要求长篇大论但要说明白为什么想到用这个算法边界条件怎么处理。写题解的过程其实就是强化题感的过程。你是在强迫自己的大脑把看懂了的模糊感觉转化成能复述、能推理的清晰结构。这个过程比多刷十道题有用得多。2. 三道热搜题拆解从会做到会讲光说不练没有意义拿几个典型的题目来拆一下。这里选的是最近热搜榜上常出现的三道LeetCode 994腐烂的橘子、LeetCode 073爱吃香蕉的狒狒以及链表类题目。这三道题恰好代表了三种最常见的解题范式多源BFS、二分答案、链表双指针。2.1 994腐烂的橘子多源BFS是一层一层扩散的思维题目是这样的一个网格里0代表空位1代表新鲜橘子2代表腐烂橘子每个腐烂橘子每分钟会让上下左右相邻的新鲜橘子腐烂问多久之后网格里没有新鲜橘子。如果不能全部腐烂返回-1。我第一次做这道题的时候有个误区我对每个腐烂橘子单独做一次BFS然后取所有腐烂橘子扩散到某个新鲜橘子的最短时间里的最大值。这样做能得到答案但效率很差而且代码写起来非常啰嗦。后来才发现正确做法是多源BFS把所有初始腐烂橘子同时当成BFS的起点。多源BFS的核心逻辑是初始化时把所有值为2的位置全部加入队列然后统一进行层级遍历。每一层遍历代表经过了一分钟层数就是结果。这里有个很容易踩的坑就是分钟数到底从0开始还是从1开始。我的经验是先把所有腐烂橘子入队用一个变量记录队列中当前层的数量然后按层处理。每处理完一层分钟数加一。循环结束后检查网格里是否还有新鲜橘子如果有就返回-1。这道题的精髓在于同时扩散这个语义。例如两个烂橘子分别从不同方向逼近一个新鲜橘子到达时间取决于距离更近的那个。如果分开做BFS就得比较多个结果一起做BFS天然就是最先到达者取胜这就和真实情况完全一致了。复杂度方面每个格子最多入队出队一次所以时间复杂度是O(m * n)m和n是网格的宽高。这个解法思路清晰、代码简洁是面试官最想看到的版本。2.2 073爱吃香蕉的狒狒二分答案的关键是找到单调性这道题的表面设定很可爱狒狒要在H小时内吃完N堆香蕉每小时吃一堆每堆只能吃一把每把可以吃K根问K的最小值是多少。实际上它是一个典型的二分答案问题也是LeetCode里最小可行速度类题目的代表。为什么可以用二分因为吃香蕉的速度K和总耗时之间是单调的。K越大耗时越短K越小耗时越长。二分答案的核心就是正向判断如果速度是K是否能在H小时内吃完然后在速度的可能范围里二分搜索最小的K。判断函数本身很简单对每一堆香蕉吃完它需要的时间是ceil(pile / K)也就是(pile K - 1) / K。把所有时间加起来如果小于等于H那么K是可行的。问题在于很多人一开始想不到对速度做二分而是习惯从1开始逐个尝试这在数据量大的时候会超时。这个题给我最大的启发是当你发现题目要求的是最小值最大值最短时间这类词的时候可以优先想一想是否存在单调关系。如果存在二分答案通常就是那把钥匙。至于二分的边界我习惯用左闭右开的写法left 1right max(piles)然后while (left right)这样写可以避免很多死循环的边界问题。判断函数放在二分循环里面每次计算一个mid然后判断是否可行根据结果收缩区间。2.3 链表类题目dummy节点和双指针几乎能解决所有面试题链表算是LeetCode里最讲基本功的题型了。它的代码量不大但非常容易出错因为牵扯到指针的移动和节点之间的断链重连。热门100题里链表题占了相当比重反转链表、合并两个有序链表、环形链表、链表的中间节点都是高频出的题。我刷链表题踩过最大的坑就是没有使用dummy节点导致头部节点需要单独处理代码写得又长又容易出bug。dummy节点的作用非常纯粹它让链表的头节点和其他节点一视同仁避免写if (head null)这种分支。比如反转从位置m到n的链表用dummy节点可以让你在操作头部区间的时候不需要额外讨论如果从头开始反转怎么办。双指针对链表来说有两个常见的应用场景快慢指针找中间节点或判断环以及间隔指针用来删除倒数第N个节点。快慢指针的原理很简单快指针一次走两步慢指针一次走一步如果链表有环两者一定会在环内相遇。这个结论本身很直觉但面试的时候需要能说清楚为什么——因为当快慢指针都进入环之后快指针相对慢指针每次接近一步所以一定能遇上。我建议链表题不要只追求写出来还要练习在纸上模拟指针的移动。面试时如果能在白板上画出每一步的指针变化通过率会高很多。这个能力没有捷径只有反复手写模拟。3. 周赛430里的几个实战信号周赛这个词经常上热搜LeetCode周赛430也是最近的一次。很多人觉得自己没实力不敢碰周赛或者参加了之后被虐得体无完肤然后陷入自我怀疑。但我认为周赛的价值不在于排名而在于暴露问题。3.1 周赛是很好的短板诊断工具周赛的四道题通常是梯度难度前两题偏热身第三题中等偏难第四题基本是竞赛级别。这意味着什么它模拟了一个真实的竞技场景让你在有限时间内快速判断每道题的难度、取舍策略和代码实现能力。我参加周赛的体验是做不出第四题很正常但如果前两题花了太长时间或者第二题写出了基本解法但没有优化到可以通过全部测试用例这说明基础还不牢。周赛的好处就是逼着你在60到90分钟之内连续处理多个不同类型的问题把所有弱点都摊开。等你回头看自己的提交记录很容易发现每次都在链表题上卡住或者一碰到动态规划就紧张这类规律。3.2 时间分配和跳跃式策略周赛里有一个很重要的策略遇到一道题看了五分钟没有明确思路就立刻先跳过做后面的题。有很多人卡在一道题上死磕最后导致后面的简单题时间不够心态也崩了。这是非常不划算的。我可以分享一个比较实用的分配方案第一题做完尽量不要超过10分钟第二题争取在20分钟内解决第三题留25到35分钟第四题能拿多少分算多少。这个方案不一定适合所有人但它背后的逻辑是通用的——优先拿下稳定的分数再挑战高分。第四题如果只剩10分钟千万不要从零开始写代码先看一下数据规模如果暴力解法能过小数据就直接暴力能拿到部分分数也是胜利。3.3 如何正确地复盘周赛周赛结束之后复盘比参赛本身更重要。我一般会按照三个步骤来做。第一步把每道题重新做一遍不看任何人的代码。做不出来就继续想直到自己写出来为止。这个过程可能比正式比赛花的时间还长但它能真正强迫你把思路理清。第二步去讨论区看别人的解法但只看思路描述不看完整代码。重点观察别人切入点和我有什么不同。比如一道题我用的是排序贪心别人用的是优先队列那就要想一想为什么优先队列更优在什么数据量下差异明显。第三步整理到自己的错题本里。错题本不抄全部代码只记录三样东西题目编号、我的思考方向、卡住的关键点。比如看到需要维护动态最大值第一反应是排序但插入频繁导致超时应该用堆。这样一段时间之后你的错题本实际上就是一份私人定制的刷题指南。4. 我整理的个人刷题指南从零基础到稳定AC最后这部分是我自己花了不少时间总结的一套可执行的路线。不一定适合所有人但它的框架是通用的你可以根据自己的基础和时间调整。4.1 第一阶段打地基只做专题不做综合题很多新人一上来就随机挑题做今天一道数组题明天一道树题后天突然蹦出个动态规划。这种乱序刷法最大的问题是你还没有形成任何套路储备遇到一个需要多个知识点结合的题完全无从下手。我的建议是前一个半月按专题刷每个专题选10到20道题从简单到中等梯度推进。推荐顺序是数组和字符串 → 哈希表 → 双指针 → 链表 → 栈和队列 → 二叉树 → BFS/DFS → 二分查找 → 动态规划入门 → 贪心。每个专题刷完不用急着做难题先确保自己能把该专题的基础题做得又快又稳。比如二分查找专题把在有序数组中查找目标值查找第一个大于等于目标值的位置查找最后一个小于等于目标值的位置这三板斧练熟。后面遇到任何二分题目判断函数可能会变但二分框架本身不用重新学。4.2 第二阶段按套路归并而不是按题号归并基础专题过完之后你会发现自己已经有了一定的题感。这个时候进入第二阶段梳理套路。常见的套路其实没那么多翻来覆去就是这些滑动窗口、前缀和、差分数组、单调栈、并查集、字典树、拓扑排序、最短路、背包DP、区间DP、状态压缩DP。每一个套路都对应一批经典题。我自己的做法是建一个表格列名是套路名称、识别特征、经典题目、复杂度。套路识别特征经典题目滑动窗口连续子数组、子串、最长/最短、窗口和无重复字符的最长子串最小覆盖子串前缀和连续子数组的和、区间查询和为K的子数组区域和检索单调栈找左右两边第一个更大/更小的元素每日温度接雨水并查集连通性、朋友圈、等价类省份数量岛屿数量BFS最短步数、最小操作次数、层序扩散腐烂的橘子打开转盘锁DFS搜索所有路径、判断可达性、组合枚举岛屿数量子集这个表格不需要一次性做完而是在刷题过程中不断补充。每当你遇到一道可以用新套路解决的题就把它写进去。等你积累了大概三十到五十个条目之后你会发现新题大多都能在表格里找到相似的身影。4.3 第三阶段按热度刷用周赛验证水平第二阶段积累到一定程度之后就可以进入第三阶段了。这个时候直接刷LeetCode热门100题但目的不是追求做完而是检验自己的套路储备够不够用。每一道题做的时候都要问自己三句话这道题在考哪个套路我第一时间想到了吗为什么没想到如果三句话都能顺利回答且代码写出来通过了说明这个知识点你已经掌握了。如果只是勉强做出来那就把对应的专题再过一遍。如果做不出来说明这个专题存在盲区回到第二阶段去补。周赛可以在这个阶段开始规律参加不建议每周都用尽全力打满但至少要保证每个月一到两次用它来测试自己的临场状态。平时刷题可以通过的题周赛高压环境下可能写不出或者写出来了但超时这些信号都非常宝贵。4.4 常见误区为什么你刷题很久却没有进步一个扎心的观察是大部分人在刷题这件事上的努力方式其实是在用自己的舒适区反复消耗时间而不是在突破学习区。具体表现为三个误区。第一个误区是只刷自己会的题。很多人坐到电脑前习惯先选择简单题因为简单题短时间能出成就感。但如果你连简单题都要花很长时间那问题不大如果你大部分简单题做起来非常轻松却还在刷简单题那就是在浪费时间了。这个阶段的舒适区需要主动打破把难度提升到有点难但想一想能解出来的程度。第二个误区是只看题解不独立思考。独立思考并不等于死磕。我给自己定了一个规则一道题十分钟没有头绪可以看题解但看完题解之后必须独立重写一遍并且用文字记录这道题的关键思路。如果连重写都做不到那说明根本没懂。第三个误区是把AC当成终点。AC表示你的代码通过了测试用例但不代表你理解了这道题的最优解法。最典型的就是暴力法过了就不再考虑优化。在面试场景里暴力解法通常只能拿到很基础的分数面试官更希望你给出最优解法并且能分析复杂度。所以我非常推荐在AC之后再做一次解法复盘去讨论区看最高票回答看完之后用这个思路重新写一遍。有些题我甚至会把四种不同做法都写一遍比如同样是二叉树的层序遍历分别用BFS队列、DFS递归维护层号、以及迭代方式实现。每种写法都会加深你对数据结构本身的理解。4.5 关于刷题节奏和心态的几点体会节奏方面我比较推荐长期主义。每周至少刷四天每天一道到两道题周末可以集中做专题或参加周赛。一次刷十个小时然后一个月不碰远不如每天稳定刷半小时。大脑对算法的熟悉感需要持续刺激来维持。心态方面不要把LeetCode的难度当成评价自己能力的唯一标准。会刷题不意味着所有工程问题都能解决但通过刷题训练出来的抽象思维、边界条件意识和代码处理能力确实会反馈到日常开发里。比如处理复杂的状态流转、并发条件下的竞态、或者接口参数校验的时候你会更自然地想到边界情况。我自己的一个习惯是手机备忘录里建了一个解题灵感列表。平时看文章、逛论坛、甚至走在路上想到某个算法问题的变体就顺手记一笔。比如看到外卖配送路径规划会想到BFS与Dijkstra的使用边界看到优惠券凑单会想到多个槽位的DP还是背包。这种把题目和现实连接起来的练习会让刷题变得不那么枯燥而且记忆更深刻。最后再分享一个小技巧做题时把函数名和参数名写得更语义化。虽然LeetCode的评测只看逻辑正确性但一个好的命名习惯能让你在面试环境中更快地理清思路。我会把BFS里的队列变量命名成queue或currentLayer把动态规划的DP表命名成dp加注释说明含义。代码是写给未来的自己看的这一点在刷题阶段就养成后面会受益很多。