刷题这件事,我前后折腾了大概三年,从最开始连“AC”是什么意思都不知道,到后来能稳定在力扣周赛拿个还过得去的名次,中间踩过的坑、走过的弯路,绝对值得拿出来说说。网上聊刷题攻略的文章很多,但要么太散,要么只讲某一部分,很少有把入门到进阶整个路径捋清楚的。这篇我试着用保姆级的口气,把刷题这件事从头到尾拆一遍:怎么选平台、怎么打基础、怎么刷算法题、怎么整理错题、怎么应对瓶颈期,全都在里面了。不管你是刚准备找实习的在校生,还是半路转码想补基本功的选手,或者已经刷了几十题但感觉很迷茫,这篇都能给你一个大概的坐标系。我尽量少讲废话,每一段都是自己实际试过、踩过、验证过的东西。
1. 刷题前,先把这几件事想清楚
很多人打开力扣(LeetCode)就开始按顺序刷,刷了十几天发现前面刷的忘光了,或者碰到稍微变形的新题就大脑空白。这种情况太常见了,根源不在于你不够努力,而是前期没把刷题这件事的逻辑理顺。磨刀不误砍柴工,刷题前的准备比刷题本身更重要。
1.1 现在刷题是不是晚了——先谈动机和精力分配
我知道很多人的第一反应是:现在开始刷题还来得及吗?我直接给个结论:来得及,但你得接受一个现实——刷题是个时间密集型的技能,短期内搞突击可以应对面试,但要真正内化成编程功底,需要至少三到六个月的持续投入。我说的持续不是每天十小时那种,而是每天一到两小时,雷打不动。你在上面花的时间,会以肉眼可见的速度体现在代码手感上。
刷题的第一步是想清楚目标。你为了什么刷题?是准备校招、社招跳槽、转码补基础,还是纯粹想提升代码能力?不同目标对应完全不同的策略。如果是为了面试,那就得优先刷高频题、经典题,后续我会给你一套优先序;如果是为了补基本功,那就按数据结构为主线慢慢推。这两个方向差得很远,如果你一开始就混合刷,很容易陷入“刷了忘、忘了刷”的循环。
我见过很多半途而废的人,死因不是题太难,而是目标不明确。今天刷一道简单题,明天碰到一道困难题卡了三个小时,心态直接崩掉。刷题的心态应该定位成“健身房练力量”,不是“期末考试突击”。前者允许你循序渐进的进步,后者只会让你焦虑得怀疑人生。
1.2 平台怎么选:力扣、Codebrick、OJ们各自的脾气
国内刷题,最主流的选择是力扣;除它之外,还有牛客网、洛谷、Codebrick、各类OJ(Online Judge),以及国外的HackerRank、Codeforces、AtCoder这些。我先聊聊它们各自的脾气,再给建议。
力扣(LeetCode)最大的优点是题库分类清晰、题解社区活跃、面试考察的题型覆盖完整。它的题目难度标注比较合理,简单、中等、困难三档基本靠谱,而且有“每日一题”“剑指 Offer”这类成体系的题目集合,很适合走面试路线的人。我个人的主力平台就是力扣,后续讲到的绝大多数套路都是建立在这个平台基础上的。
Codebrick这类学习型平台,适合刚入门还在学语法和数据结构的阶段。它往往不是让你上来就写代码,而是用可视化、分步引导的方式让你理解算法过程。坦白讲,这种模式对完全零基础的人很友好,但对已经有一些代码经验的人来说可能略啰嗦。你可以把它当作入门辅助工具,但别停留在舒适区太久。
洛谷和各类OJ则是更硬核的存在。它们大多源自竞赛场景,题目刁钻、边界数据狠,而且几乎不给提示,适合想冲击算法竞赛或者已经把基础打牢之后去虐自己的人。我在入门阶段用洛谷做题经常WA(Wrong Answer)到怀疑人生,后来才发现不是我的代码逻辑错了,而是IO输出格式跟题目要求差一个空格。OJ平台就是这种方式:严苛、不近人情,但也确实能锻炼人。
我的建议很明确:面试导向的,主刷力扣,辅助牛客做笔试题;竞赛导向的,主刷洛谷或Codeforces。两个方向的门道不太一样,但都不建议一上来就在多个平台之间反复横跳,精力真的会被分散掉。
1.3 时间和节奏的安排——我用过的两种方案
刷题的时间安排,我实践过两种方案,各有优劣。第一种叫做“固定时段型”,每天选固定的时间刷,比如晚上八点到十点,雷打不动。优点是容易养成习惯,适合自律性一般的人;缺点是一旦被临时安排打乱,当天的任务基本就废了。第二种叫“灵活碎片型”,早起刷一两道简单题热手,午休时看题解,晚上集中攻坚一道中等题。优点是灵活,缺点是容易变成“只刷简单题”的舒适区循环,因为人的本能会逃避难题。
我的实际经验是,前期用固定时段,后期转碎片型。前期需要高强度建立体感,固定时段能形成肌肉记忆;刷到两百题以后,基础能力已经上来了,碎片型反而效率更高。无论如何,有一点要忍住:别以刷题时长来感动自己。坐在那里三个小时只刷了一道题,和四十分钟高效刷两道题并复盘,后者的实际效果更好。建议以题数为单位做记录,而不是以时长为单位。
2. 基础阶段的必经之路:从搭环境到打出第一份AC
进入正式刷题之前,先把运行环境准备好。这个步骤很多人不重视,直接在力扣网页里写代码,结果到了面试现场或者笔试系统里,连本地调试都不会,瞬间原形毕露。我建议每个人都建立一套本地刷题环境,哪怕再简陋,也得有。
2.1 语言选型和环境热身
刷题用什么语言,这个问题争议很大。我的观点是:如果你不是指望它吃饭的底层语言开发者,就用你面试最熟的那门语言。面试官看重的是你的解题思路和代码风格,不是你会多少门语言。用不熟的语言刷题,等于同时学算法和语法,双重打击,最容易放弃。
我自己主力是Python,理由很简单:语法简洁,写数据结构操作尤其快,能让你把精力集中在思路上而不是语言细节上。但Python有个坑,就是运行效率相对偏低,有些题目要求极高时间复杂度时可能TLE(Time Limit Exceeded)。如果你的面试岗位明确要求Java或C++,那就直接用对应的语言刷,别为了省事用Python,到时候面试还得换语言,又是新一轮的适应成本。
环境配置的核心就三个东西:编辑器或IDE、调试工具、顺手的一套代码模板。我个人的组合是VS Code + Python插件,配合本地终端跑测试用例。刷题的时候,我会先把题目里的示例输入复制到本地,手动构造几条边界数据,跑通后再粘贴到力扣的代码框里提交。这个习惯帮我避开了大量“本地能跑,一提交就错”的尴尬情况。
2.2 必刷基础算法题,到底哪些才叫基础
很多新手问我“基础算法题该刷哪些”,我会给出一份相对精简的清单。你不需要把力扣上两千多道题都刷完,但以下这些类型必须覆盖:数组、字符串、链表、栈与队列、哈希表、二叉树、排序与搜索、双指针、滑动窗口、动态规划基础、贪心算法基础、回溯算法基础。在这些类型里,每个方向找十到二十道高频题来刷,足够支撑起面试所需的基本盘。
我把最核心的题型整理成一个表格,方便你对照自查。表中的优先级是我个人的排序,供你参考。
| 题型方向 | 代表题(力扣题号) | 难度阶梯 | 优先级 |
|---|---|---|---|
| 数组与哈希表 | 两数之和、三数之和、字母异位词分组 | 简单到中等 | 最高 |
| 链表 | 反转链表、环形链表、合并两个有序链表 | 简单到中等 | 最高 |
| 二叉树 | 二叉树中序遍历、最大深度、层序遍历 | 简单到中等 | 最高 |
| 双指针与滑动窗口 | 无重复最长子串、盛最多水的容器 | 中等 | 高 |
| 动态规划 | 爬楼梯、打家劫舍、最长递增子序列 | 简单到中等 | 高 |
| 回溯算法 | 全排列、组合总和、子集 | 中等 | 高 |
| 贪心算法 | 买卖股票的最佳时机系列 | 简单到中等 | 中 |
为什么把数组、链表、二叉树列为最高优先级?因为它们是所有复杂数据结构的基石。你后面学图、堆、并查集,底层逻辑都离不开这三种结构的操作。我见过很多人一上来就死磕动态规划,结果连续卡了一个月,连链表反转都要想半天,那就是优先级排错了。先把最简单的结构吃透,建立正向反馈,再逐步上难度,效率会高很多。
2.3 面对一道陌生题的标准操作流程
刷到不会的题太正常了,关键是你怎么应对。我总结了一套面对陌生题的操作流程,每次照做,基本能稳定推进。
第一步,读题并提取输入输出。把题目的示例自己手动跑一遍,搞明白它问的是什么。第二步,先想暴力解。哪怕你心里清楚暴力解大概率TLE,也要先写出来,因为它是优化思路的出发点。第三步,分析暴力解的瓶颈,想怎么优化。是空间换时间,还是排序后简化问题,或者用双指针把O(n^2)降到O(n)。第四步,写出优化解,手动跑示例。第五步,想边界情况。空输入、单元素、全相等、负数、超大数、溢出,这些情况逐个过一遍。
这套流程看起来简单,但真正做到的人很少。很多人卡在第二步:总觉得暴力解太“丢人”,非要直接想要最优化解。实际上,我的经验是,大多数中等难度的题目,从暴力解出发推优化,是最高效的路径。因为暴力解给了你一个正确的基线,优化方向就有了参照。别怕暴力解,它是你通往最优解的第一级台阶,不是丢人的产物。
3. 核心细节解析:刷题过程中最容易忽略的几件事
刷题这事,表面上是个“做题”的活儿,内里考验的其实是方法。很多人把刷题做成了刷数量,一天五道十道,像完成任务一样划过去,结果一个月下来还是那个水平。我接下来要说的几个细节,是我认为决定刷题质量的关键点,也恰恰是最容易被忽略的。
3.1 看懂题解比自己闷头想更重要
很多刷题攻略会告诉你“不要看题解,要自己想”。这话对了一半。对于难度较高的题目,硬想三个小时没思路,不但浪费精力,还会把自信消磨掉。我的经验是:给自己设定一个时间阈值,简单题十分钟、中等题二十分钟、困难题三十分钟。过了这个阈值还没思路,就去看题解,但看题解的方式有讲究。
首先,只看题解的核心思路,不看现成代码。先把思路用自己的话复述一遍,然后关掉题解,自己写。写在纸上、写在编辑器里都行,但一定要写完、跑通。如果你看完了题解却直接抄一遍提交,那你收获的东西基本为零。其次,看题解时多对比几种解法。力扣热门题解里往往有大佬给出多种思路,比如同一道题既可以用动态规划,也可以用贪心。把两种思路都理解了,你对这类题目才算真正入门。最后,看完题解后建议做一道同类的题目来巩固,这就是很多攻略里提到的“趁热打铁”。力扣的题目页面下方有相似问题推荐,直接点进去做就行。
3.2 代码风格与命名,从一开始就要认真
刷题有没有必要在乎代码风格?我的回答是:太有必要了。笔试可能会做代码查重这种机制化的处理,但面试时面试官会现场看你的代码,代码风格就是第一印象。变量命名别再写a、b、c了,哪怕你是一个人在刷题,也要养成使用有意义的命名习惯。比如双指针叫left和right,数组下标叫index或i、j,状态转移用dp这个通行的缩写,循环里的中间变量叫temp也说得过去。
代码的可读性还包括结构上的整洁。你写完一个函数,是不是立刻就刷答案走人?我建议多花一分钟,把代码里的缩进、空行、注释稍微整理一遍。好的代码风格不是面试加分项,而是基础项。我甚至建议你在刷题时就用面试的标准来要求自己:在白板或编辑器里写完整流程,边写边解释思路,别等着提交AC了才回头补功课。这个习惯一旦养成,面试时你会非常有底气。
3.3 错题本到底该记什么,怎么记才有用
广大刷题者最大的误区之一就是不记错题,或者记了也没用。我见过一些同学,错题本记得密密麻麻,但记录的内容是“某月某日,某道题,答案链接”,这跟没记有什么区别?一份能用的错题本至少应该包含这四个要素:题目编号与难度、你自己的错误思路、正确思路的核心步骤、你用到的数据结构或算法技巧。不要抄题,也不要抄代码,只记录关键点和思路。
我的个人方法是按“刷题知识点”分类整理,而不是按时间。比如我在“二叉树”分类下积攒了很多错题,每次刷到类似专题,就先翻一遍这类错题,温习一下自己的错误模式。这个习惯带来的提升是复利式的:每刷一轮,错题本里的知识就在脑子里加深一遍。如果你也在坚持刷题却觉得进步有限,不妨检查一下自己的错题本:它到底是一个答案仓库,还是一个思考过程的记录器?答案大概率是前者,所以没效果。
3.4 边界条件与极端输入的处理
“我的代码示例全过了,为什么一提交就WA?”这个问题的头号凶手就是边界条件没想全。我总结过几种高频边界场景:数组为空、链表只有一个节点、元素全相同、数值为负数、输入极大需要long long/大整数处理、目标值不存在、存在多个重复答案需要去重。这些情况,在写代码的时候就该提前想清楚,而不是等WA了再找。
我自己曾经在力扣刷一道中等题时,本地跑通了所有示例,结果提交WA了好几次。后来发现问题是输入数组长度为1时,我的滑动窗口初始化判断没覆盖,直接导致越界访问。这个错误非常典型,因为示例给的数组通常比较长,你不会下意识去验证极端短的情况。从那以后,我每写完一道题,都会在提交前手动测试几个边界用例,虽然看起来花时间,但实际上节省了往返提交和等待的更多时间。
4. 实操过程与核心环节:一个完整的刷题闭环长什么样
前面讲了许多理论和方法,这一节我想把一次完整的刷题过程,从选题到复盘,原原本本地摆出来给你看。你跟着走一遍,就知道什么叫“有效刷题”。整个闭环包括五步:选题、审题、编码、验证、复盘。哪一步都不能缺。
4.1 选题:按专题集中训练,而不是随机挑题
选题直接决定了你刷题的效果。我最不推荐的就是“随机模式”,打开力扣首页,看到哪道顺眼做哪道。这样做题碰到什么学什么,完全形不成知识体系。我坚决推荐“专题模式”:选定一个知识点,比如“滑动窗口”,把力扣上相关的经典题一次性找出来,集中刷。这些题不会单独出现在你面前,但是你在一个时间段内反复用它,大脑就会自动归纳这一类题型的共性。
拿“滑动窗口”举例,经典题目包括:无重复字符的最长子串、字符串的排列、最小覆盖子串、长度最小的子数组、滑动窗口最大值。这些题看似各不相同,但它们的核心框架高度一致:定义窗口左右边界,移动右边界扩张窗口,碰到不满足条件时移动左边界收缩窗口,窗口内维护一个计数结构或聚合值。当你把这几道题连着刷完,框架感就出来了。以后见到类似题目,你甚至可以套模板思路,而不是从零开始推理。这就是“集中刷专题”的意义所在。
4.2 审题:用“翻译”替代“解读”
审题这件事,说难很难,说简单也很简单。我推荐的方法是:把题目“翻译”成你自己的语言。比如一道题描述“给定一个整数数组和一个目标值,返回两个数在数组中的下标,使它们的和等于目标值”,翻译过来就是“在数组里找两个元素,它们的和是target,返回下标”。最后你再把“限制条件”也翻译出来:“元素只能使用一次吗?数组有序吗?有重复吗?”这些翻译都是在帮你提炼题目的本质,防止理解偏差。
很多人栽在审题上,不是因为阅读能力差,而是过度“解读”。什么叫过度解读?就是自己脑补题目没有的条件,或者忽略题目的关键细节。举个例子:题目说“返回任意一种答案”,结果你为了生成字典序最小的答案费了半天劲;题目说“数组已排序”,你还在自己手写排序。审题不是阅读理解,它更像翻译,原文写什么就是什么。这个过程建议控制在三到五分钟以内,别在理解题目上消耗过多时间。
4.3 编码:先写伪代码,再写真代码
我强烈建议写代码之前先过一遍伪代码。伪代码不用管语法,就是描述逻辑流程。比如“先对数组排序;然后遍历每个元素作为第一个数;再对剩余部分用双指针查找两数之和”。把这个流程写出来,你会发现整个代码的骨架就已经清晰了,剩下的事情就是把这个骨架翻译成语言。
有一个很典型的错误习惯是一上来就敲代码,敲到一半发现思路错了,推倒重来。这种情况其实很普遍,根源就是脑子里只有一个模糊的方向,没有完整流程。伪代码就像你去一个陌生地先用导航看一遍路线,真代码是实际开车。虽然看起来多了一步,但实际总时间反而短。我自己刷题刷到后期,也会先在注释里把思路写出来,再填充实现细节。这种方法在面试时还能起到跟面试官沟通思路的作用,一举两得。
4.4 验证:不只是跑通示例,而是对抗性测试
示例通过不等于代码正确,这件事很多新手要踩几次坑才明白。我自己有一个“对抗性测试”的习惯:把示例跑通之后,主动想几个刁钻的测试用例,把手写代码的边界能力测一测。比如反转链表这道题,我会测试空链表、单节点链表、两个节点链表、环形结构(如果允许);对于涉及排序的问题,我会测试全等元素、降序输入、大量重复数字等情况。
对抗性测试的核心思路是“故意挑战代码,而不是验证代码”。你越跑偏门用例,越能提前发现隐藏问题。如果测试阶段发现自己写的优化解跑了个普通用例反而比暴力解慢,那说明分析不够充分,这时候回到纸上重新分析过程,而不是硬着头皮提交。
4.5 复盘:把一道题变成一类题的关键一步
很多攻略把复盘说得很玄乎,其实复盘的核心就三个问题:这道题我一开始为什么没做出来?卡在哪个环节?下次遇到类似的题,我第一反应应该是什么?这三个问题想清楚了,这道题的价值就吃透了。
我每次刷题结束后,会在错题本上记录上述三个问题。比如“没做出来的原因是,惯性思维只想到了DP,但其实用双指针可以更快”“下次一看到有序数组+查找目标值,先思考双指针方向”。日积月累之后,你的错题本实际上就是一本“思维字典”,每次遇到新题,你翻一翻这个字典,很多同类型的题目都能迅速找到对应的解题思路。这也是为什么有些刷题大神看起来一眼能看出解法,不是他们聪明,而是他们的“思维字典”足够厚。
5. 常见问题与排查技巧实录
刷题过程中一定会有各种让你崩溃的时刻。这一节我把自己和身边人踩过的坑整理一下,分成心态、技术、环境三个维度,逐个拆开聊。这些问题非常典型,我相信你绝对会遇到至少其中一个。
5.1 刷了一个月感觉没进步,怎么办
“我刷了三十天,每天打卡,但碰到新题还是不会,是不是我太笨了?”这个问题几乎每个刷题的人都问过自己。先下结论:你没变笨,你只是没形成“题型识别能力”。刷题前期的进步不是线性的,它更像是登阶梯:前面几十道题是铺垫,你感觉不到什么变化;到了某个临界点,大概在一百道左右,你会突然发现很多题能摸到方向了,这个感觉非常奇妙。
如果你刷了一个月还没找到感觉,优先检查两件事。第一,是不是一直在刷自己熟悉的题型,逃难式地回避不擅长的方向?如果每天刷的都是简单题,那确实进步有限,因为你在舒适区打转。第二,是不是只看题解不动手?这种情况最常见,进度显示刷了八十几题,但真正自己完整写出来的不超过二十道,那当然没效果。可以自己做一个简单的统计:近十道题里面,有几道是你没看题解自己写出来的?如果少于五道,请立即调整策略,减少题量,增加独立思考的时间。
5.2 提交后显示TLE,先不要急着优化
TLE是超时的标志,看到这个结果不要慌,按顺序排查。第一步,检查有没有死循环。很多TLE其实是while条件写错,导致循环根本出不去。第二步,检查是不是用了过重的数据结构或算法。比如在循环里反复调用list.index,复杂度O(n^2)很容易超时。第三步,考虑空间换时间,提前用哈希表/集合存储中间结果。第四步,如果以上都没有问题,再考虑算法层面的降复杂度,比如从O(n^2)优化到O(n log n)。
我见过不少人在TLE后直接重写整个算法,结果越改越乱。我的建议是先定位再优化,就像调试一样,先确认瓶颈在哪个环节,再对症下药。实际上,力扣题目设计时,对时间复杂度限制通常比竞赛OJ要宽松,很多用例用一般优化就能过。TLE大多数情况下问题出在细节上,而不是宏观算法上。
5.3 本地运行正常,一提交就报错,怎么办
这种问题是最让人头疼的。它背后的原因通常是环境差异、输入输出格式问题或者未初始化变量。首要排查项是输入输出格式。力扣这类平台已经帮你封装好函数了,你只需要实现接口。但如果你在Codebrick或OJ上做题,往往需要自己处理标准输入输出,一次输出多个结果时要注意等号对齐、空格、换行符。我曾在OJ上调试了半小时,最后发现是自己的print语句多打了一个空格,那种懊恼感现在回想起来还记忆犹新。
另一个原因是全局变量或未初始化数据。力扣会在一组测试用例中多次调用你的函数,如果函数里用了全局变量且没有在每次调用前清零,就会出现行为不一致。这个坑在树和图的题目里尤其常见。解决办法很简单,一律把需要用到的变量都写在函数内部,尽量避免使用全局状态。
5.4 刷题的“尴尬期”:中等题能看懂但不会变通
当你刷到一百多题的时候,会进入一个“中等题能看懂,但稍微变一下就不会了”的尴尬期。这是好事,说明你不再是小白了,但也说明你还没形成自己的解题框架。破局之道只有一个:横向对比同类题。把相同知识点的题目放到一起回顾,你会发现它们的解法骨架高度相似。举一个例子:动态规划的核心无非是定义状态、找状态转移方程、初始化状态、确定遍历顺序。凡是DP题,你从这四步入手,至少有八成题目能走通一个大概思路。同理,回溯题的套路是:路径选择、终止条件、剪枝。二叉树题的套路是:递归遍历时的前中后序怎么安排、每层返回什么。
这个阶段不要求你做出困难题,但要求你在面对一道中等题时,能先判断它属于哪个专题,再给出基本的解题骨架。哪怕你实现细节有偏差,或者边界处理漏了,那都没关系,骨架对了,剩下的都是细节。如果一道题你连它属于哪个专题都判断不出来,那就说明你的横向对比做得还不够,继续回上一关补功课。
5.5 如何利用好每日一题和竞赛
力扣的每日一题和每周周赛,都是极好的训练材料。每日一题的好处是零成本、无负担,适合当作热身。它的难度分布比较随机,可能连着好几天都是简单题,也可能突然来一道困难题。我的用法是:简单题就直接做,当巩固;中等题当成当天的主线任务;困难题如果二十分钟没思路,看题解但不纠结。
周赛则是模拟真实面试状态的好机会,四道题由简到难,限时约一个半小时。我建议有一定基础的人每周都参加,不用太在意排名,重点是体验在时间压力下分析问题、写代码的全过程。第一次参加周赛可能会紧张,代码写得乱七八糟,这都很正常。多参加几次,你会逐渐适应这种节奏,面试时的临场感反而会缓解很多。另外一个隐藏价值是,周赛题目经常会成为后续面试的高频题,很多公司面试官自己都不一定意识到,他们的题目就是从某场周赛里扒的。
6. 进阶方向:从会刷题到会思考
当你的刷题量到达两百到三百题以上,你对很多基础题型的套路已经驾轻就熟。但这并不代表你可以停下进阶的脚步,因为真正拉开人与人差距的,是对算法思想的理解深度,而不是会做多少道题。
6.1 从“记模板”到“推导模板”
基础阶段我们一直在强调记忆模板,比如滑动窗口模板、二分查找模板、DFS回溯模板。但到了进阶阶段,你需要做到的恰恰是“忘记模板,理解推导”。你不再是在刷题时匹配“这题用二分”,而是能够从题目本身的条件出发,判断它为什么能用二分,以及二分查找的哪个变体才适合当前场景。
举个最简单的例子:二分查找。写过多次的同学下意识就能写出标准版本,但真正问你“为什么while条件是left <= right而不是left < right”,可能很多人会卡住。这就是模板记忆和原理理解的差异。进阶阶段的学习方式,应该是主动对每一道题问“为什么这个解法能行,这个算法的时间复杂度为什么是这样,如果条件改一点会变成什么”。这个过程看起来很慢,但它复利很高。刷题量到了一定程度,限制你的不再是手速,而是思维方式,这时候原理理解就成了唯一的增长点。
6.2 复杂数据结构与算法专题的拓展
基础题型全覆盖之后,进阶的丰富度一下子就打开了。你可以往这些方向拓展:图论的Dijkstra、Floyd、拓扑排序、并查集,树形DP、状态压缩DP、线段树、树状数组,字符串匹配KMP、字典树Trie,以及组合数学、数论相关的应用型题目。这些内容初看很难,实际上各有各的逻辑体系,而且很多知识是網状相连的。
我的建议是每个方向选三到五道经典题精刷,力求弄懂原理,而不是贪多。比如并查集,你先找三道题:冗余连接、岛屿数量、账户合并。把这三道做透,你对并查集“连通性”的应用场景就会建立起扎实的直觉。再比如树状数组用在“频繁修改+频繁前缀查询”的场景,你能不需要看题解,独立地把它写出来,那就算真正掌握了。进阶阶段的题数可以降下来,但每一题花的时间要成倍涨上去。
6.3 代码效率和细节规范再上一个台阶
进阶阶段要开始在意执行效率了。很多基础阶段能过的解法,到进阶阶段可能TLE,原因不是你逻辑错,而是常数项太大。举几个常见优化点:能用数组就别用字典,能用本地变量就别频繁调用全局函数;Python里频繁拼接字符串要用列表收集再转字符串,而不是写进循环里累加;递归深度过大时要考虑转为迭代式;排序时可以自定义比较函数,用对比较规则能省掉额外处理逻辑。
与此同时,代码规范也要向工程化靠拢。多写类型注解、提取重复逻辑、保证函数短小、语义清晰。我觉得刷题到后期,它给职场带来的回报已经不亚于面试本身了,因为你写代码的习惯会被一点点磨练得干净利落。这个阶段结束后,你会发现自己看生产环境代码时的感觉也不一样了,别人写出来的混乱代码,你甚至会有一种本能的不适感。
7. 一点私货:刷题之外的配套打法
刷题本身解决的是“代码题”这一类能力,但要真正在面试和工作中脱颖而出,光靠刷题还不够。我一直有一个想法,刷题只是底线,不是上限。我想在最后分享几个刷题之外的习惯,它们可能不是“刷题”这个标题的直接内容,但对刷题效果有巨大加成。
多读别人高质量的代码。力扣题解区有很多代码风格极好的作者,他们的写法简洁、命名清晰、注释精准。我有一次在翻一道困难题的高赞题解时,发现作者在代码注释里写了完整的时间复杂度推导过程,那个阅读体验真的舒服。从那以后,我养成一个习惯:刷完一道有价值的题,会顺手翻三五篇不同人的题解,不是为了比较谁写得快,而是为了学习不同的代码表达方式。时间长了,你的代码审美会提高,自己写代码时也会下意识地追求更好的表达。
把刷题和你正在做的事结合起来。如果你在学前端,很多数组、字符串、链表的概念其实和DOM树遍历、状态管理有隐性的相通之处。如果你在做后端,你会发现在设计接口、处理批量数据时,很多算法思想直接能用上。刷题不该是空中楼阁,它的最终价值要落在实际的工程能力上。我见过一个做数据平台的同学,因为刷过大量前缀和的题,在处理增量数据报表时想到了用前缀和优化,直接让接口耗时降了一个数量级。这种例子在真实职场里并不少见。
关于刷题的量,我不喜欢定一个绝对的数字指标。常有人说“刷了三百题才能进大厂”,这句话给你的是一个焦虑,不是一个方法论。我见过刷了六百题的人面试翻车,也见过只刷了一百五十题但基础扎实的人拿到好offer。差别就在于,前者把刷题当任务,后者把刷题当工具。如果你真的能把每一个专题吃透,把每道做过的题都复盘到位,哪怕只刷了两百题,你的实战水平也绝对比那些草草刷过八百题的人强得多。
我自己最开始刷题时也走了不少弯路,浪费了不少时间在没有意义的题量上。后来逐渐摸索出“专题刷题+错题复盘+横向对比”这套方法后,感觉每一步都踩在实地上。如果你看到这里,说明你大概率也准备认真对待刷题这件事。那就别急着找捷径,先从手里的第一道简单题开始,把它做透,再往前走。刷题这条路,慢就是快。