发布时间:2026/10/12 2:42:07来源:迅启考通分类:考试资讯文章详情以下为资讯详情页模板:正文区域由后台内容渲染,图片与正文将自动替换为对应文章内容。翻看这一两个月的算法刷题记录我发现一个很反直觉的事有人刷了两三百道题新题一出来还是只会写最笨的暴力版本有人只精刷了一百来道笔试碰到变形题却能很快定位思路、给出接近最优的解。差距不在天赋而在刷题的方法论。这篇刷题总结我打算换个写法不一次性堆题单、不罗列代码而是把这几个月在主流算法在线判题平台上踩过的坑、理清的思路、沉淀出来的做题框架完整写出来。内容包括动手前怎么确定目标和节奏、从暴力到最优解的真实思考链路、高频题型怎么拆解、复盘该怎么做、面试手撕代码前要注意什么。无论你是准备求职、应付笔试还是想把算法基础重新夯实这篇应该都能给你一些可以落地的参考。1. 先别急着开刷目标、节奏与方法论多数人刷题失败不是因为不够努力而是起跑姿势就错了。拿到平台账号后第一件事不是开刷而是想清楚“我到底为什么刷题”。目标不清晰很容易陷入刷了忘、忘了刷的循环。1.1 三类刷题人的目标差异按理说刷题都是为了“通过考试”但仔细分一下人群其实有三种对应的最优策略完全不同。第一类是为了应付线上笔试。笔试特点是题量大、时间紧、自动判题只认结果所以这类人更适合优先背常见模板刷高频题追求的是“见过的题能在规定时间内写出来”。第二类是为了面试手撕代码。面试现场考察的不只是跑通面试官更看重你如何分析问题、如何权衡时间空间复杂度、写出的代码边界是否干净因此沟通和推导过程比“秒AC”重要得多。第三类是为了真正理解算法底层比如想深入搞懂动态规划、图论的本质那就要做一题多解、追源码细节速度反而放慢。我在初期犯的错就是目标混着来既想着笔试多得分又想着面试能讲清楚结果每天东刷一题西刷一题隔一周就忘。后来我把目标收敛成“以面试手撕为第一优先级顺带覆盖笔试高频题”规划才开始有效。建议你在第一步就做这个卖定这三个目标里你现阶段最看重哪个哪者为重其他为次。1.2 数量不是KPI可复现的思考过程才是我见过两类典型学习者。A同学每天在平台刷十道新题三个月下来数字很好看六百多道但发表在笔试里碰到一道“合并区间”的变形题都能卡住因为他只记住了原题的解法没有把“排序后贪心维护边界”的思路抽象出来。B同学每天只精做一两道但每道题都会先写暴力解再看怎么优化最后查题解对照思路在备忘录里记一段“为什么当时没想到”三个月只刷了一百道笔试和面试表现却稳定得多。刷题真正要积累的不是AC数量而是思考路径的可复现性。你能不能在拿到新题时不慌按一套稳定的流程去推断数据范围提示什么复杂度有没有重复计算的子问题能不能用双指针、哈希、二分这些套路去套这些才是题目的养分。所以我在后期给自己定了规矩每天至少一道新题但必须保证“今天做的这道题下周没有任何提示还能独立写出来”。凡是不满足这个条件的都不算真学会。1.3 推荐的学习节奏和选题策略节奏方面我实际验证下来比较舒服的方式是工作日每天一到两小时做一道中等题周末留出整块时间做专题训练和复盘而不是散着刷。语言建议只认准一门主语言最好与你面试目标岗位一致因为算法题的模板代码量不大但语法要熟到不用想。写题时不要另一门语言对照着看会分散精力。选题策略上我踩过一个很大的坑从题号小到大顺序刷。平台前几百题难度并不递增而且类型混得很乱今天链表明天动态规划形不成体系。正确的做法是按专题刷比如第一周数组与哈希、第二周双指针、第三周二叉树把一个专题吃透再换下一个。难度比例建议简单两成、中等六成、困难两成。困难题不是不能碰但前期刷太多容易挫伤信心性价比也低。2. 三道代表性题目从暴力到最优解的完整思维链很多教程喜欢直接给你最优解然后让你背。可真实面试里你先想到的一定是暴力解然后才逐步优化。这一章我用三道非常经典的题目演示完整的推导链条包括复杂度计算和边界判断让读者明白“最优解不是凭空蹦出来的而是顺着问题结构一步步逼出来的”。2.1 两数之和为什么哈希表是必然选择题目要求返回数组中两个下标使两数之和等于目标值。绝大多数人第一时间会写双重循环这是完全正常的起点。先算一笔账假设数组长度 n10^5双重循环的执行次数大约是 n^2/2也就是 5×10^9 次在常规判题环境下远超1秒限制。所以暴力解能过小数据但碰见大数组就稳挂。优化的关键要落到一个问题上第一层循环确定了一个数 a我们需要快速知道“ target - a ”是否在数组里以及它的下标。前一次循环慢在哪儿慢在每次都要再遍历一遍数组去找另一个数。那能不能一次性把“值到下标的映射”记下来哈希表就是干这个的。给它一个值平均 O(1) 就能返回对应的下标。于是算法变成遍历数组每看到一个数 a先查哈希表里有没有 target - a有就直接返回没有就把当前 a 和它的下标存进表里。这样整体时间复杂度 O(n)空间复杂度 O(n)。很多讲解把哈希这步说得轻而易举但我想强调一个排查心得如果题目要求不能使用同一元素两次必须“先查表再存表”。先存再查的话当 target 是某个数的两倍时你会把同一个下标返回两次。这个细节我在笔试里栽过一回。def two_sum(nums, target): seen {} for i, num in enumerate(nums): diff target - num if diff in seen: return [seen[diff], i] seen[num] i return []2.2 爬楼梯动态规划的状态定义与滚动数组题目背景每次可以爬1级或2级台阶问爬到第 n 级有多少种不同方法。这题看着像组合计数实际上背后是一个非常典型的动态规划模型。先想暴力递归到达第 n 级要么从第 n-1 级迈一步上来要么从第 n-2 级迈两步上来。所以 f(n) f(n-1) f(n-2)边界 f(1)1、f(2)2。问题是直接递归会重复计算大量子问题比如 f(5) 会算两遍 f(3)时间复杂度指数级。动态规划的价值在于把子问题结果存下来每个子问题只算一次。具体到这个题状态定义就是“dp[i] 表示爬到第 i 级台阶的方法数”转移方程就是上面那个递推式最终返回 dp[n]。还有个细节很多人忽略递推从 i3 开始向后算只需要两个中间变量不用开 n 长度的数组因为每一次只依赖前两个状态这叫滚动数组优化。优化以后时间复杂度 O(n)空间复杂度 O(1)在平台判题中成绩会好很多。def climb_stairs(n): if n 2: return n prev, cur 1, 2 for _ in range(3, n 1): prev, cur cur, prev cur return cur我想额外说一个我在面试中问过别人的点这题虽然表现形式是“爬楼梯”但它的本质和斐波那契完全一样只要把递推关系想透后面遇到“跳台阶”“铺地砖”“兔子繁殖”都能瞬间迁移。会一题不重要能在新题里认出这个递推结构才算真的会了。2.3 搜索旋转排序数组二分法的边界条件如何处理这道题难度立刻上来了。数组本来是升序的但在某个未知的位置旋转了一下例如 [0,1,2,4,5,6,7] 变成 [4,5,6,7,0,1,2]。目标是在 O(log n) 时间找到给定值。有序数组查找第一反应是二分可这里整体并不是单调的所以很多人会卡住。核心洞察是把数组从中间切开左右两半必然有一半是严格升序的。以 [4,5,6,7,0,1,2] 为例mid 指向7左半边 [4,5,6,7] 升序右半边 [0,1,2] 也升序。我们每次只需要判断 target 在哪一个升序区间里。怎么写代码判断 nums[left] nums[mid] 是否成立若成立说明左半边有序再看 target 是否落在 nums[left] 到 nums[mid] 之间落在就缩小右边界否则去右半边找反之处理右半边有序的情况。这里不得不提一个真实的坑判断到底是用还是。当数组长度为偶数、左右指针相邻时如果写成 nums[left] nums[mid]mid 可能等于 left导致某一步区间不再缩小进入死循环。稳妥的写法是用 保证左半边包含 mid。我建议在本地多跑几组特殊用例长度1、旋转点在开头、target 就在边界上。这些用例能筛掉绝大多数细节错误。def search_rotated(nums, target): left, right 0, len(nums) - 1 while left right: mid (left right) // 2 if nums[mid] target: return mid if nums[left] nums[mid]: if nums[left] target nums[mid]: right mid - 1 else: left mid 1 else: if nums[mid] target nums[right]: left mid 1 else: right mid - 1 return -1这类题的思考链条让我意识到二分法的本质不是“数组有序”而是“可以判定答案在某一半的范围内”。旋转数组正好具备这种性质理解到这一层才算真正摆脱了死记模板的阶段。3. 高频题型拆解套路、模板与易错点量刷到一定程度后你会发现算法题是可以归类的。这一章我整理一份高频题型速查表再挑几类最常见的题型展开讲模板和常见失误点。它的目的是让你在考场上快速完成“识别题型 → 选用套路 → 落地代码”这三步。题型典型识别特征常用复杂度目标双指针/滑动窗口连续子数组、子串最值、两数之和O(n)前缀和子区间和、区间计数O(n) 预处理DFS/BFS矩阵连通、岛屿数量、树的遍历O(n)回溯组合、排列、棋盘类枚举指数级需要剪枝单调栈下一个更大元素、柱状图矩形O(n)堆/TopK第K大、合并有序链表、数据流中位O(n log k)动态规划最值、计数、存在性且存在重叠子问题O(n) 或 O(n^2)并查集连通分量、朋友圈、冗余连接近似O(n)字典树前缀匹配、单词搜索建树O(总字符数)图论最短路径带权图最短路径、最小花费Dijkstra O(E log V)3.1 双指针与滑动窗口连续子数组问题的统一解法双指针看起来简单实际上有两个方向。第一种是相向指针典型场景是“有序数组里找两数之和等于某个值”。左指针指向开头、右指针指向末尾根据和与目标的大小关系移动一边时间 O(n)。第二种是滑动窗口典型场景是“无重复字符的最长子串”“长度最小的子数组”。窗口右指针不断向右扩展同时维护一个窗口内状态当状态不满足要求时左指针收缩直到重新满足。模板看起来是这样def sliding_window(s): left 0 window {} ans 0 for right, ch in enumerate(s): window[ch] window.get(ch, 0) 1 while 不满足条件: window[s[left]] - 1 left 1 ans max(ans, right - left 1) return ans滑动窗口最常见的错误有两个。一是没想清楚什么时候收缩左边界这取决于你对“窗口是否满足题意”的定义建议先把判定条件写在注释里再写代码。二是忽略了窗口内元素的频率变化只计数不更新导致 right 移动时状态是错的。我的经验是先大声说出窗口维护的是什么信息再动手。比如“无重复字符最长子串”窗口里各字符出现次数一旦某个字符次数大于1左边界就要右移直到该字符次数回到1。3.2 二叉树题目递归框架与终止条件的经验法则二叉树题是笔面试中出镜率最高的类型之一但只要掌握统一框架性价比极高。递归写三个东西函数返回值是什么、终止条件是什么、单层逻辑怎么处理。以“二叉树最大深度”为例返回值是当前子树的最大深度终止条件是节点为空返回0单层逻辑是取左右子树的深度最大值再加1。再以“判断平衡二叉树”为例返回值变成“这棵子树的高度以及是否平衡”实质是把自底向上的信息带上来。我踩过的坑在于终止条件经常漏判。比如“判断两棵树是否相同”终止条件不只要考虑都为空返回 True还要考虑一棵空一棵不空返回 False否则后面访问 node.val 直接空指针。还有一种情况是递归层数过深在平台判题时出现递归栈溢出比如数据范围 10^5 的单链表题这种情况可以换成迭代写法。二叉树递归的核心不是背模板而是想清楚每层递归往上传什么信息、往下传什么参数。3.3 回溯算法当暴力解需要剪枝时回溯就是带撤销操作的深度优先搜索常用于组合、排列、子集、棋盘这类“枚举所有可能”的问题。它的代码骨架很固定先判断是否到达终点记录结果然后遍历所有候选分支做选择递归撤销选择。难的是剪枝条件。举一个具体区分求组合 [1,2,3] 中选2个数的组合和求全排列。组合对顺序不敏感递归时传入 start 参数下一层只能从当前下标之后开始避免重复排列则要传一个 used 数组保证同一元素不被重复使用。很多人把这两个模板混用结果组合问题跑出了大量重复答案。剪枝的核心想清楚这一层能选哪些分支、哪些分支一定不可能出解。比如求和目标超过 target 时排序后提前终止循环性能会大幅提升。def backtrack(path, start): if len(path) k: result.append(path[:]) return for i in range(start, n): path.append(nums[i]) backtrack(path, i 1) path.pop()回溯的直觉对应到现实就是“走迷宫”。每到一个岔路口选一个方向走到死路就退回上一个路口换方向。写代码时最容易出问题的点是路径数组忘记在递归返回后撤销结果所有分支互相污染。建议把 path.append 和 path.pop 成对书写养成肌肉记忆。3.4 单调栈一类容易被忽略的优化利器单调栈不像哈希和双指针那么直观很多刷题前期的人根本没听说过但它能解决一类看似只能暴力解决的问题。典型例子是“每日温度”给定每天温度返回要等多少天温度会升高没升高用0表示。暴力解法双循环 O(n^2)数据一大就很吃力。单调栈的思路是维护一个栈栈中元素从栈底到栈顶单调递减遍历每天温度时一旦遇到当前温度比栈顶对应温度高说明栈顶那天的“下一个更高温度”就是今天弹出并记录答案然后当前下标入栈。为什么它能把时间复杂度降到 O(n)因为每个元素最多入栈一次、出栈一次到整体复杂度就是线性的。单调栈的难点是脑子里要同时维护“下标”和“值”两层信息。我习惯于栈里装下标比较时再通过 nums[stack[-1]] 取值这样答案需要下标时直接取。这也是典型的“空间换时间”案例看似多用一个栈实际上省掉一层循环。遇到“下一个更大元素”“柱状图中最大矩形”“接雨水”这类题目建议优先考虑单调栈方向。4. 复盘与错题整理拉开差距的隐藏环节刷题最容易忽略、但性价比最高的环节是刷完之后的复盘。很多人的状态是“AC 了就下一题”然后同类题再见面时照样不会。我后期能稳定提高靠的是建立了一套轻量、可持续的复盘系统。4.1 我的复盘模板与记录字段我在表格工具里维护了一份刷题记录每个题一条字段不多但很关键。先看长这样字段说明示例日期做题时间2025-01-12题型归入哪一类二叉树的递归是否独立AC未经提示写出否耗时从读题到提交成功35分钟错误原因一次错误的核心递归终止条件漏判最优解思路复盘后写清后序遍历向下返回高度时间复杂度写清楚O(n)关联题目同类可迁移题最大深度、最小深度一句话收获最容易遗忘的要点递归先想好返回什么记录的意义不是形式主义而是逼你重写一遍思路。我通常做题后先不急着看题解自己试着把思路写出来写不出来再去看题解然后用红笔标注“卡在哪个节点”。一段时间后回看很重要的一条经验是“不会做”和“做错”是完全不同的两件事分开记会让你更清楚自己的薄弱点到底在哪。4.2 错题分类错误原因决定了你的处理方式我把自己做错的题分成五类每类的处理策略完全不同完全不会做对题型陌生需要从题解里补充新的思维模型隔天重做一遍再找两道同类题巩固。会做但超时说明暴力思路可通但缺一个复杂度优化点重点学习如何用哈希、双指针、前缀和之类去掉内层循环。边界条件错误比如数组越界、空输入、单个元素。这类问题不是概念不懂而是测试习惯差以后每次写完代码先自测3个边界用例。题意理解错大多数是没读清楚“最多”“至少”“连续”这类限定词。建议读题时把约束条件划线尤其注意数据范围。手滑低级错误变量名写错、把 nums[i] 写成 i、忘记更新返回值等。这类只需在提交前做一次“代码走读”逐行对照变量名。我给身边朋友的一个建议是一周内出现的错题数量超过20道说明刷题量超负荷了该减速。没有复盘消化的刷题只是自我感动。错题本的作用不是“记答案”而是用来发现自己的思维盲区。比如我连续三次在滑动窗口的收缩条件上出错才知道自己对“窗口状态定义”的理解不够牢固。4.3 一题多解与多题一解建立知识迁移复盘到了高级阶段我会刻意做两件事同一道题追求多种解法、不同题寻找同一个底层模型。拿“两数之和”来说除了哈希解法如果数组有序还可以排序加相向双指针并顺手推导时间空间权衡。拿“最长递增子序列”来说既可以用动态规划 O(n^2)也可以用贪心加二分的 O(n log n) 版本。这两种解法背后的思维方式完全不同DP看重子问题递推贪心加二分看重有序序列维护。多写一种解法相当于多学一个算法套路。反过来的方向是“多题一解”。很多题目看起来不一样实质是同一个模型。比如最短路径和最小生成树都起源自图论中的贪心背包问题可以变形为多重背包、完全背包、分组背包数位统计题和区间DP都有覆盖区间的共性。我在复盘时如果发现两题解法结构一致会合并到同一条记录并写一句“这道题换了个外壳内核是XX”。久而久之新题就不再是全新的而是旧模型的变体。这种抽象能力才是刷题带来的最大红利。5. 三个月备考周期与面试手撕现场的细节方法讲得再多最后还是要落到一张可执行的时间表和一套现场应对流程。这一章我提供本人实践过的备考周期安排以及面试现场手撕代码容易忽略的细节和踩坑清单。5.1 三个月划分基础、专题、模拟我的完整备考周期一般定在三个月上下。第一个月打基础目标是把核心数据结构和基础题型过一遍数组、链表、哈希、栈和队列、二叉树遍历、简单动态规划。这个阶段允许做简单题重点把语言的常用 API 写熟。第二个月进入专题攻坚每周定两个专题比如周一至周三做双指针和滑动窗口周四至周五做回溯和动态规划周六日做综合长题。第三个月转入模拟阶段每天固定一套时限的模拟题题目难度从简单到困难随机混合按真实笔试节奏来安排时间。实际执行中要注意一个量平衡基础阶段一天两三题可以专题阶段一天一到两题更能保持质量模拟阶段重在“限时”和自我检测。期间如果连续两天做题效率明显下降那就说明疲劳了用半天时间只复盘错题不写新题比硬撑着刷十道废题更有效。很多人一上来就定每天五题的硬指标大概率因为不可持续而放弃。定一个稳定输入的小指标更容易长期坚持。5.2 面试手撕代码动手前的三分钟比写代码更重要现场面试和在线笔试最大的差别是面试官想看到你如何思考而不是只看到最终代码。我的经验是先花三分钟做四件事再动键盘。第一重复一遍题目确认输入范围、是否有序、是否有负数、数组长度等边界。第二说暴力解法并计算复杂度让面试官知道你能想到基线思路不是只会背答案。第三抛出优化方向比如“这里每次查值都要遍历所以我想用哈希表把查询变成 O(1)”让面试官看到你的推导过程。第四商量清楚了再写代码。代码写完后不要着急说“完成”自己先走两个测试用例再指出可能越界的边界条件。很多面试评分不会因为你最后没跑通就否定而会看你在调试过程中能不能快速定位问题所以我建议平时就养成“写完自测”的习惯而不是依赖平台立刻反馈结果。还有个小技巧尽量把主逻辑抽成清晰的小函数减少一次函数里做的事情现场调试时会轻松很多。5.3 我踩过的几个典型坑最后一个部分列几个我真实摔过的跟头希望你能绕开。第一个是把动态规划题当成贪心做。有段时间看到“最多”“最少”就直接上贪心拿到“跳跃游戏II”这类题时想当然跳最远结果思路错了。确认是否贪心的关键是想清楚这个局部最优是否一定导致全局最优不确定就用动态规划或搜索兜底。第二个是二分法里区间边界写成死循环。最典型的是 while left right 和 while left right 混用加上 mid 取整方向不一致出现死循环。我给自己定的规范是这个只要用 while left rightmid 取 floor更新边界必须写成 left mid 1 和 right mid - 1这样区间一定会收敛。第三个是忽略了数据溢出。比如求两个整数中间值时直接写 (left right) // 2当 left 和 right 都很大时可能溢出写成 left (right - left) // 2 更安全。这类问题小型测试用例不会暴露但在边界数据下就是致命的。第四个是递归栈溢出。刷高频树题时习惯递归一旦题目数据范围走到 10^5 甚至更大Python 默认递归深度很容易爆栈。遇到这种题要么手工转迭代要么提前调整递归深度。我在平台提交时吃过几次亏现在写递归前会先看数据范围再决定写法。第五个是不管空间复杂度。很多暴力解法时间很紧张但我曾经只盯着时间完全没有意识到有些题目还限制了额外空间。比如“寻找多数元素”要求 O(1) 空间哈希方案直接不合格只能上投票法。刷题时看到“常数空间”“原地修改”这类词就要立刻切换算法方向。回头看这段刷题经历我最大的体会是真正让人进步的不是做的题目数量而是花在“把一道题彻底想透”上的时间。你可以从今天开始挑一道上周做过的题目不看代码重新推导一遍思路如果能顺利讲出为什么用这个解法、坑在哪里说明那道题才算真正归你所有了。保持这个节奏刷下去下一道新题再出现时你会发现它不过是个换了件衣服的老朋友。特别提醒:考试时间、报名批次等安排如有调整,以河南省应急管理厅及官方考点最新通知为准。