
刷题记录这东西看着不起眼真要坚持下来却比刷题本身更考验人。我自己的账号hetao1733837上过去三天3月10日到12日正好完成了一轮密集刷题总共21道覆盖双指针滑动窗口、二叉树递归和动态规划三条主线。整理完这三天的记录我最大的感受是记录的价值不在“今天又AC了几道”而在它能把零散的思维过程变成以后能复用的经验。这篇不打算贴流水账而是把这三天的题单设计、记录方法、踩坑过程和一些反复出现的解题套路都拆开讲清楚让同样在刷题的朋友能直接拿过去参考。先说这三天适合谁。如果你已经过了“连题目都读不懂”的阶段开始能写一些简单题的解法但遇到中等偏上的题目经常卡住、测试用例过不全、看了题解又觉得自己啥也没学到那这篇应该能给你不少启发。我这次的所有题都不涉及冷门数据结构不考脑筋急转弯全部是面试笔试中出现频率很高的经典问题所以题单本身的含金量还是可以的。1. 三天刷题计划的整体设计思路1.1 为什么把周期定成三天我见过很多人刷题特别喜欢定一个月计划、百日刷题计划结果往往是前一周热情高涨后面就直接断档。我自己试过几次“长假特训”发现到了第五天就开始疲效率断崖式下跌。后来就改成一个周期只做三天大概对应一个周末加一个工作日晚上或者反过来三个工作日的碎片时间无论多忙都能挤出一点保证余量。三天的好处在于它足够完成一个相对完整的小闭环——从选题、做题、整理模板到复盘、应用、查漏可以不紧不慢地走完又不会长到让新鲜感耗尽。这次我严格按三个晚上的节奏来每晚大概一个半小时到两个小时白天碎片时间看看题解和别人的讨论整体没破功。另外三天也是形成一个“专项”的比较合适的边界。单一知识点的题目连续做三天到第三天基本能看出自己是否真正掌握——如果换个包装还是不会说明还没到火候如果可以快速识别考点并写出稳定解法那这个点就算过关了。1.2 题量目标与难度配比我这次定的目标是三天21题平均每天7道。这个数字经过一点计算不是拍脑袋拍的每晚有效刷题时间约100分钟简单题平均8-10分钟中等题平均15-25分钟难题可能要35到45分钟甚至更久。如果全做中等题一晚上7道确实偏紧所以需要留2到3道简单题用来热身和保持节奏。最终的实际配比是简单7道、中等10道、困难4道刚好在“挑战但能坚持”的区间。这里有个小经验不要每天都塞困难题。困难题最消耗认知资源处理起来经常要读题加思考超过30分钟连续做容易产生强烈的挫败感。我习惯把困难题安排在某些专项的第三天那时已经在前两天的题里积累了足够的熟练度再碰难题会更有底气。1.3 这轮刷题想定向解决什么跨平台、跨公司的题目千变万化但不能每次随机乱做。我这次选的方向非常明确双指针与滑动窗口处理数组和字符串问题的万能套路很多暴力超时的题都能用它优化到线性二叉树递归与DFS/BFS递归思维是后续动态规划、回溯、图论题目的基础二叉树是这个思维的绝佳练习场动态规划入门到进阶我最大的薄弱点之前一看状态转移方程就头大这次想系统地练一串递进式的题目从记忆化搜索逐步过渡到真正的DP。三个方向按天数分配第一天全部给双指针和滑动窗口第二天集中做二叉树第三天转为动态规划。看似互相独立其实暗含连贯性——第一天练的是“通过单调性减少枚举”第二天练的是“把问题分解成子问题”这两件事恰恰是第三天DP状态转移的核心思维。等到第三天做DP时很多题看上去已经不是新题了。2. 刷题记录模板与复盘方法2.1 一个真正能坚持的记录格式很多人记刷题记录就是简单抄一下题号和答案回头翻的时候完全不知道当时在想什么。我用的格式复杂一点但字段都经过筛选长期维护成本低信息密度高字段内容示例为什么记录日期2026-03-10看自己节奏是否稳定题目主题无重复字符的最长子串直接对应考点类型滑动窗口方便归并同类难度中等评估配比是否合理耗时18分钟判断是否卡太久错误类型边界条件-窗口左移错题分类汇总用核心收获右指针固定右移左指针在条件不满足时收缩提炼成自己的模板复习标记下周复习安排遗忘曲线这个表格看起来字段不少但每题其实只需要两三分钟就能填完。真正关键的是“核心收获”这一列我会用一句大白话把解题思路写下来比如“这题就是双指针右边的先进左边根据约束条件后退中间维护一个窗口状态”。这种用自己的话写的解释比复制题解里的官方描述有用得多因为大脑对熟悉的语言加工过的信息记得更牢。2.2 卡住多久应该看题解这是刷题圈争论最多的问题之一。我的标准是中等题15分钟没有完整思路难题20分钟没有从样例反推出可行方法就立刻转去看题解。很多人觉得看题解就是失败其实不然千万别在不该花的时间上硬耗。看题解也不是直接往下翻答案。我的操作是先只看思路的第一句话比如“使用滑动窗口维护一个哈希表记录字符最后出现的位置”然后就关掉题解自己重新推。这样既避免了在原地打转又保留了主导解法的思考过程。如果只到第一句话就能完全写出来这题在记录里会专门标一个“提示即可AC”的标签说明这个考点已经接近掌握。真正的问题不是卡15分钟还是20分钟而是看了题解之后直接抄抄完就下一题。那种行为不叫刷题叫打字练习。看题解后至少要能独立写出代码并让它在评测系统里通过这步我从不省略。2.3 错误分类与错题本设计把做错的原因归成五类方便后续定向补弱思路缺失型完全不知道用什么算法这种题需要整理算法的适用信号边界条件型数组越界、空输入、单元素、负数这类细节纯靠经验积累实现转化型思路清楚但代码写不出来说明coding基本功还不够复杂度不达标型能做出来但超时需要思考更优解法理解偏差型读题读漏条件或者样例看错老司机也会翻车。这次21道题里我最主要的错误来源是第二类和第四类尤其是滑动窗口题目经常忘记循环里收缩指针的时机动态规划则是用二维数组的思路推到了一维怎么办、dp数组初始化的边界到底定义什么语义。错题本按这五类标记之后哪块弱一目了然——我明显看到“边界条件型”占比接近四成说明以后刷题前要刻意给自己加一堆边界用例再提交。3. 三天题单详解与核心题型拆解3.1 Day1双指针与滑动窗口专项第一天一共7道题简单3道、中等3道、困难1道。整体逻辑是从最基础的相向双指针逐步过渡到同向双指针也就是滑动窗口。先说相向双指针。典型场景在一个有序数组里找两个数使得它们的和等于目标值。最直觉的写法是双层循环但时间复杂度是O(n²)。改用一左一右两个指针如果当前和大于目标就把右指针左移小于目标就把左指针右移这样最多O(n)就能搞定。这个解法的核心依据是单调性——因为数组有序指针移动的方向才有确定的意义。我第一晚先做两题找感觉这类题代码量少价值在于建立“双指针优于暴力枚举”的敏感度。然后进入滑动窗口。滑动窗口的套路我总结成四句话右指针负责扩左指针负责缩窗口数据在扩缩时同步更新答案在每次右指针移动后统计。以“无重复字符的最长子串”为例它的关键点是左指针跳到重复字符上次出现位置的下一位而不是一位一位挪。我第一次写就错在这里只想到while左移没利用哈希表跳到直接位置结果最坏情况退化成O(n²)被测试数据直接教做人。后来改成存储字符最近出现的位置后时间降回O(n)判题一次通过。这也是为什么滑动窗口题特别适合“复杂度不达标型”错误——思路对了但细节不对性能就露馅。当晚的困难题是“最小覆盖子串”这类变体本质仍是滑动窗口但多了个need变量来统计缺口。这类题的通用写法骨架我在下方代码里用伪代码的形式展示出来初始化窗口数据结构如哈希表need、窗口计数window、left0、valid0 for right in range(len(s)): 把s[right]加入window 如果window中的计数满足needvalid加1 当valid等于需要覆盖的所有字符数时: 尝试更新答案 把s[left]移出window 如果window中的计数不再满足needvalid减1 left加1 返回最小窗口这个骨架几乎能套用于绝大多数“子串/子数组最值”问题。第一天结束我的记录表里已经能看到双指针从“知道两个指针”进化到“知道什么时候移动哪个指针、移动后更新什么”的层面。3.2 Day2二叉树的递归与DFS/BFS第二天同样7道题把重点放在“递归处理树结构”的两种经典写法自顶向下的前序式递归以及自底向上的后序式返回合并。这两类写法几乎覆盖了二叉树80%的题目剩下的则是层序遍历的BFS。关于递归最需要扭转的思维是不要试图在脑子里完整展开每一层调用栈。我第一天做“二叉树的最大深度”还在一层一层手推函数调用到“判断平衡二叉树”这种需要子树返回是否平衡时彻底想晕了。后来改用“假设子树已经处理完当前层只用它的结果做判断”的思维代码很快就清晰了。这是一种典型的“信任递归”的心态刚开始别扭习惯之后效率大涨。层序遍历的BFS模板相当固定我用一个简单的示意代码帮助记忆queue 初始放入根节点 while queue 不为空: level_size len(queue) 当前层列表level [] 循环level_size次: 弹出一个节点加入level 如果左孩子存在入队 如果右孩子存在入队 把level加入结果列表 返回结果这个模板优先用len(queue)固定当前层节点数而不是直接在while里弹出这样层级才不会乱。第二天晚上我把层序遍历、右视图、锯齿形遍历放在一起做其实就是同一个模板改一点点输出策略。练习到这种程度BFS基本就能形成肌肉记忆。这里有一个必须提醒的细节递归深度。在处理较深二叉树时Python这类语言默认递归深度约1000层有些构建得很极端的测试树可以直接把程序干到“递归爆栈”。要注意两点一是能转成迭代就转成迭代二是递归函数先想清楚终止条件和返回值语义再动手。第二天我就碰到过一次递归深度超限后来用显式栈模拟递归问题立刻消失。3.3 Day3动态规划基础过渡第三天7道题难度拔高简单1道、中等4道、困难2道。内容从记忆化搜索开始一步步过度到标准DP写法。这个过渡我认为是学DP唯一顺畅的路径——千万不要一上来就啃状态转移方程。以“爬楼梯”为例第一步先用递归解决比如f(n)f(n-1)f(n-2)。但直接递归会重复计算大量子问题这时引入记忆化数组缓存中间结果就得到了“记忆化搜索”。第三步才是观察计算顺序自底向上用数组填表。先递归、再记忆化、最后迭代填表三个步骤逐层递进状态转移方程是在这个过程中自然涌现的而不是从天而降的。当天最耗时间的困难题是编辑距离系列。它的二维DP数组是经典模型状态定义为“前i个字符和前j个字符之间的最小操作次数”。转移时如果两个字符相等直接继承左上方结果如果不相等取增、删、改三个操作的最小值加一。这道题我完整走了“暴力递归—超时—加记忆化—通过—整理迭代DP—再AC”的全流程整个过程耗时约70分钟但这个完整链条比刷五道简单题都值钱。Day3结束后我把三天的知识线画了一张思维导图双指针利用单调性降低枚举维度二叉树递归本质上就是把大问题分解为子树问题DP则是在子问题有重叠时缓存计算结果。这三者在“分治与优化”这个主题下顺利汇合对后续学习图论、回溯、贪心都能平滑迁移。4. 实操过程从读题到AC的完整链路4.1 读题与样例分析的要点很多人做题习惯看完题目立刻写代码这是最低效的做法。我这次执行了一套固定的破题流程每一步都有明确产出。第一步圈出题目的输入规模。看到“数组长度最大10^5”那O(n²)基本可以直接枪毙暴力枚举方案放弃。看到“数据量只有100”O(n²)甚至O(n³)都可能接受。这个快速复杂度预判极大地节省了试错时间。第二步自己动手跑两遍题目给的样例。这一步很多人会跳过但它能验证对题意的理解正确。我会把样例输入拆成边界场景在纸上模拟指针或状态如何变化顺带检查有没有“题目没明说但样例暗示了”的特殊要求。比如滑动窗口类题有的要求返回窗口本身有的只要求返回最大长度这决定了记录窗口状态时是否要额外保存下标。第三步强迫自己用三句话总结题意。例如“在一个只包含小写字母的字符串中找最长的连续子串使得其中没有重复字符返回长度”。能说清楚这句话说明你已经抓住了题目核心后续即使写不出代码查题解时也能精准定位知识点。4.2 从思路到伪代码的关键一跳思路正确但代码写不出来是很多人的常态。我习惯先把伪代码写出来再写真实代码。比如做滑动窗口时先写“右指针移动更新窗口while条件不满足左指针移动更新答案”然后再把每个步骤对应成具体的数据结构操作。伪代码的作用是隔离“逻辑设计”和“语法实现”两个层面的复杂度。先只关注逻辑不管语法细节等逻辑清晰了再一次性翻译成代码。这样写出来的代码明显比边想边写干净得多出错率也大幅下降。我统计过这次三天里凡是先花5分钟写伪代码的题平均调试时间少了差不多一半。伪代码里我还会显式标出边界条件的处理位置比如“注意当left右移时要同步更新窗口内的字符计数”“dp数组初始化时第0行第0列的含义要写注释”。这些注释可能看起来不重要但在你回看记录时会非常有用能一下子回忆起当时的坑在哪。4.3 复杂度估算与优化取舍判题系统里常见的错误除了答案错误就是超时和内存超限。在提交前做一次复杂度自测是很必要的习惯。比如“两数之和”用哈希表能把时间从O(n²)降到O(n)但如果数组本身已经有序双指针在空间上更优不需要额外哈希表。我在Day1做一道有序数组双指针题时先写了哈希表的解法提交通过但看到提示里要求“尝试不使用额外空间”才意识到自己的解法不够符合题目倾向。后来换双指针重写代码长度更短空间O(1)。这件事给我的教训是AC不一定是终点判断一道题是否掌握还要看是否理解了题目设计者想考察的解法。用最优复杂度思路写答案面试时才能说出“为什么不用额外空间”。做题时我还习惯在提交前先心算一次最坏情况将n10^5代入我的复杂度公式看运行时间上界大约是多少毫秒。如果明显在这个量级会跑不动就回过去重新想不要抱着侥幸心理提交。4.4 一个晚上完整刷题的节奏控制这三天的晚上我按下面这个节奏执行稳定而且不容易疲惫时间段内容0-15分钟热身复习昨天的错题和模板做一道简单题15-70分钟核心期刷2-3道中等题每道不超过20分钟70-100分钟攻坚期再刷1道困难题或整理复杂题类型最后10分钟填写记录表归类错误安排次日计划这个节奏的关键是“热身—核心—攻坚”的递增。一上来直接做难题很容易挫败先用简单题把状态调动起来再逐步加强。而且我严格设定核心期每道题的时间上限超了就标记超过不恋战。这样即保证了题量也保证了每天都能留下完整记录。到第三天晚上结束时我还给自己留了一个小尾巴把Day2和Day3的所有错题重新扫一遍确保不是“当晚会做第二天全忘”。5. 每天刷题后的总结与知识点串联5.1 用知识图谱代替零散记忆曾经我也是一天刷完就觉得完事大吉后来发现过了一周什么也不记得。从今年开始我每晚结束前都会花10分钟把当天题目的考点画进一张小地图里。比如Day1的地图围绕“双指针”展开相向型、同向型滑动窗口、快慢型三个分支每个分支下面挂我今天做过的题号和考察点。这样不是记单个题而是记一个网络做题时按网络索引提取速度会快很多。这张知识图谱不需要美观我用的是随手笔记本只写关键词和连线。重点在绘制的过程里大脑会强制对题目做分类和归纳这本身就是一种记忆强化。比如我画Day2的地图时发现“二叉树的所有路径”“路径总和”这类题看似不同其实都是前序递归加参数传递的变体于是把它们归纳在同一个分支下。下次遇到“路径总和II”就知道该往这个方向想。5.2 题型的迁移与举一反三刷题到一定量以后最宝贵的能力就是“看到一个题目想到另一个会做的题目”。这次三天里我遇到好几次题型迁移Day1的“无重复字符的最长子串”迁移到Day1的“最小覆盖子串”窗口收缩条件从“有重复”变成“覆盖全”本质只是哈希表统计要求变了。Day2的“二叉树层序遍历”加一个“按层翻转”或“只输出最右侧节点”就变成了不同的题但BFS框架完全不变。Day3的“打家劫舍”和“最长递增子序列”前者是选或不选的状态决策后者是枚举前一个位置进行转移核心都是“每一步决策依赖前一步结果”的DP模型。我会在记录表的“核心收获”字段里专门写一句“这题的XX思想等于Day1的XX题”把跨题连接显式记下来。三天下来这个连接网络越来越密做题时的选择就不再是碰运气而是有据可循的迁移。5.3 把解法提炼成自己的模板每做完一批同类型的题我会把共同骨架抽出来用自己能理解的语言沉淀成模板。模板的作用不是背答案而是提供思考的起点。比如滑动窗口的骨架、BFS的骨架、DP二维数组的转移骨架都是这三天沉淀下来的成果。写模板时有一个潜在陷阱不要直接抄网上的总结一定要自己从做过的题里总结哪怕一开始总结得很笨拙。自己生成的模板理解得深遇到变体时才知道哪个部分可以改、哪个部分是固定的。比如滑动窗口里“右指针固定左指针条件收缩”这个骨架我根据自己做题中卡住的地方补充了“什么时候更新答案最省事”这张更细的地图最终这套模板短小精悍基本够用。6. 常见问题与排查技巧实录6.1 判题超时的排查思路我这三天的21道题里有过3次超时记录。每次超时我都按下面这个顺序排查先确认复杂度。如果复杂度本身是O(n²)而n已经到10^5那换算法是唯一出路再排查常数优化。有些题复杂度正确但常数太大比如频繁创建新数组、不必要的对象拷贝、哈希表用得不恰当能改成局部变量和基础数组就改最后检查是否陷入死循环。滑动窗口题目超时很可能不是复杂度问题而是while左移条件写反导致指针不动无限循环。我印象最深的是Day1的一道滑动窗口变体答案始终不正确且运行超时。断开调试后发现左指针在每次迭代开始时被重新赋值成了初始值导致窗口永远没缩小。这类问题光看根本发现不了必须借助在小样本上加打印、观察指针的移动轨迹来定位。有条件的话把判题失败的用例复制到本地用十几行的样例结合print看过程很快就水落石出。6.2 思路对但代码答案是错的这个情况几乎人人都有。我的经验是先把代码和伪代码逐行对照看逻辑在翻译成语法时是否出现偏差再看初始化值是否合理比如记录最大值的变量初始化为0还是负无穷、最小值的变量初始化为正无穷还是数组首元素差一个符号结果完全两样最后检查索引上下界比如循环里right的范围到底是len(s)还是len(s)-1dp数组要不要开成n1。Day3的“编辑距离”我就在初始化上摔过跟头。dp[0][j]应该表示“从空字符串变到j字符需要插入j次”结果我一不小心初始化为0导致整个转移表建立错误以后的答案全部偏低。这种错是最气人的题目你懂、思路也对就挂在基础定义上。后来解决方案是在白板上把小规模表格手工推一遍亲手填出前两行两列初始化问题就直接暴露了。6.3 三天后坚持不下去怎么办很多人不是能力不够而是做不到“持续”。我自己三天的节奏能坚持下来靠的不全是意志力而是一个简单的机制每天的目标在头一天晚上睡前就定好精确到题号和难度第二天按清单执行就可以。执行时不需要再花时间做决策心理负担骤减。如果某天实在状态差到完全不想刷我会采取“保底策略”只做一道最简单的题5分钟解决然后填记录表。这个动作虽然微不足道但保持了“连续”的感觉避免出现断档。刷题最怕的不是某天少刷而是断掉后再也没有动力捡起来。记录表上连续三天的勾本身就是很好的正反馈。三天刷完不是终点我通常会休息半天然后把错题全部重新提交一遍再挑一道同类但没做过的题快速检验。如果你也打算按这个模式来一次三天专项记得核心不是“刷完21道”而是“刷完还能说出每类题型的骨架、常见坑和可迁移的解法”。我自己这个账号hetao1733837里其实存着一整条漫长的记录线过去都是从某一天开始、在某一天断掉。这三天之所以值得写出来是因为它终于不再是随机碰运气式刷题而是形成了从选题到记录再到回顾的完整闭环。根据我个人的体会刷题记录最大的意义是让未来的自己不再害怕相同的坑踩第二次。