news 2026/10/13 7:21:33

算法面试高频题型梳理与刷题复盘方法论

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法面试高频题型梳理与刷题复盘方法论

经常有人问我:算法题到底怎么刷才有效?网上题库动辄几千题,今天刷一道明天刷一道,最后面试该不会还是不会。我自己也经历过那个阶段,后来索性把所有碰过的题目重新做了一遍梳理,按照题型、难度、考点重新归档,就成了这个叫“部分算法题”的项目。它不是那种全量题库搬运,而是把最高频、最核心、最容易在面试里考到的题型抽出来,配上解题思路和模板代码。这篇文章我就好好讲讲这个项目是怎么设计的、里面那些题到底该怎么拆、怎么做才真正消化掉,以及我自己实测下来踩过的一堆坑。

适合谁看?如果你正准备技术面试、刚开始刷题找不到方向、或者刷到几千题但在手写代码时还是卡壳,这份梳理的思路应该能给你一个可复用的框架。我尽量少讲虚的,多讲怎么落地,毕竟算法这玩意儿,最终看的还是你能不能在白板上写出能跑的代码。

1. 内容整体设计与思路拆解

1.1 为什么只保留“部分”题,而不是全盘照搬

市面上算法题总量太大,其中大量题目要么是数学脑筋急转弯,要么是各大题库为了凑数量堆出来的变体。真要全刷一遍,这辈子基本就交代在这上面了。所以这个项目一开始就定了个原则:只保留“值得反复做三遍以上”的题目。

什么叫“值得做三遍”?我的判断标准有三个:第一,这道题背后代表了一种独立的解题范式,比如二分答案、单调栈、状态压缩、树上差分,做过一次它能辐射一整类题;第二,它是面试里出现频次极高的题型,比如链表反转、LRU缓存、最长回文子串这一类;第三,这道题踩坑价值高,也就是它能在某个细节上把你虐到怀疑人生,做完之后能让你对某个知识点有更深的理解。

按这个标准筛选下来,最终留下的题大概覆盖了十几个核心考点区域。比起按数量堆积的题库,这种筛选更像是“最小可复现知识集”:每一道题都是一个锚点,面试时遇到新题,先在脑子里匹配锚点类型,再套范式,最后填细节。

1.2 按“面试考查权重”设计归档维度

刷题不能按题号顺序刷,那样太被动了。这个项目的归档方式是按两个维度交叉划分的:第一维度是数据结构,数组、链表、栈与队列、哈希表、树、图、堆、并查集;第二维度是算法思想,二分、递归回溯、深度优先搜索、广度优先搜索、贪心、动态规划、分治、滑动窗口、双指针。

这两个维度交叉之后就形成了一张网格,每道题都能落到网格的某个格子里。面试官出的题再怎么变化,也逃不出这张网格的范围。你在搜索一道算法题时先别急着看题解,先自己想它属于哪个格子。这样做的好处是长期下来你在大脑里建立了一张“题型地图”,而不是零散的一堆孤立解法。

1.3 应对面试场景的特殊设计考量

说实话,面试算法题和平时做练习题有本质区别。平时做题你可以翻书、打断调试、搜资料,但面试现场白板写码拼的是“短时间内快速定位解法”和“手写代码一次写对”的能力。所以这个项目在归档时额外标注了几项面试针对性指标:

第一是高概率高频题,这类题必须做到肌肉记忆级别,也就是闭着眼睛能把模板敲出来;第二是低概率冷门题,这类题了解原理即可,不必追求一次通过;第三是临场易错题,专门汇总那种思路对但代码老写错边界的题;第四是思路讲解复杂度,用来判断一道题适合用几分钟向面试官讲清思路。

我后来带过几个同学模拟面试,发现很多人在白板上卡住的根本原因不是不会算法,而是对题型的定位太慢。有的题一看就是典型动态规划,他先犹豫了五分钟“这题是不是可以用双指针”,说明他脑内的题型地图不够清晰。这个项目里专门设置了“一眼定题型”的练习环节,用的就是这些归档好的题目。

2. 高频题型分类与典型题目拆解

2.1 数组与双指针:最简单的容器,最深的坑

数组这块我建议从双指针入手,它既能解决很多问题,又不像动态规划那样一上来就把人劝退。但数组看似简单,实际坑非常多,尤其是边界条件。这个项目里归档的典型题包括有序数组去重、盛最多水的容器、三数之和、接雨水等。

以三数之和为例,它的核心思路是先排序然后固定一个数,再用双指针去扫剩余区间。但不看题解自己写一遍的话,十个人有八个会栽在“去重”这一步:去重不能只针对外层固定的数,内层双指针移动时也要去重,否则结果里会出现相同的三元组。很多解法讲的时候说得轻巧,等到手写代码的时候就在这个细节上露馅。

再比如接雨水这道题,暴力能过但这题白做了。它真正的价值在于让你理解“按行算”和“按列算”的区别,然后自然引出单调栈解法。这类题我的建议是做完之后一定要把复杂度重新分析一遍,并且能用不同方法各自实现一次,才算是真正吃透了。

经验之谈:数组题的边界条件建议养成一个习惯,在写代码之前先用一句话说清楚区间定义,比如“左闭右开”还是“左闭右闭”。很多边界错误都是因为前后区间定义不一致导致的。

2.2 链表:递归和迭代的那个经典交接点

链表题在面试里属于“大家都觉得自己会,但一写就乱”的类型。这个项目里归档了链表反转、合并两个有序链表、环形链表检测、链表排序、K个一组翻转链表等经典题。

链表反转是一个所有解法的基础,但很多人以为背个迭代代码就完事儿了。实际上这道题真正要掌握的是“三种形态的统一理解”:迭代反转、递归反转、头插法反转。很多人面试时被问到“你用递归实现一下”,当场卡住,就是因为他只会背迭代,没理解递归反转里每一步到底在返回什么。

K个一组翻转链表更是高频,它考察的对链表操作的熟练度非常高。难点不在于翻转本身,而在于“前一组和后一组之间怎么接起来”。我的做法是先把大问题拆成两个子问题:写一个翻转区间内的函数,再在链表上循环调用它。只要这两个子问题各自清晰,整体思路就顺了。

2.3 二叉树与递归:别把递归想复杂了

树和递归是密不可分的,因为树结构的定义本身就是递归的。这部分归档了前序中序后序遍历、二叉树的最大深度、验证二叉搜索树、最近公共祖先、二叉树的层序遍历、路径总和系列等题目。

我给这类题目定了一个心法:不要试图在脑子里模拟完整的递归栈,而是只关注“当前节点要做什么,然后相信递归”。比如翻转二叉树,很多人第一次做的时候试图把整个递归过程想清楚,反而把自己绕晕了。正确的做法是:如果当前节点是空,返回空;否则交换当前节点的左右子树,然后递归处理左右子树。至于底层怎么一层层翻转上来的,交给递归,不用操心。

验证二叉搜索树这道题是个经典陷阱题,看起来很简单,用中序遍历是否有序就能解。但如果题目要求你直接用递归判断每个节点和左右子树的关系,很多人就会写上“只检查当前节点是否大于左子、小于右子”这种有漏洞的代码。正确做法是把每个节点的取值范围作为参数传下去,而不是只和直接子节点比较。

注意:二叉树相关的递归代码,写完之后一定要检查“空指针”这个分支。我见过太多人的树类题死在不处理空节点上。

2.4 动态规划:最难啃但也最值得啃的硬骨头

动态规划是整个算法面试里区分度的最大来源。很多同学第一步就卡在“到底怎么判断一道题能用动态规划解”上。判断标准其实很朴素:第一,问题能分成互相独立的子问题;第二,子问题之间有重叠;第三,存在一种状态定义能把子问题的答案存下来。

这部分归档的题目按递进关系排列:爬楼梯、斐波那契数列这种入门题;不同路径、最小路径和这类二维网格题;打家劫舍、买卖股票这类序列决策题;最后是背包问题、编辑距离这类需要更复杂状态压缩的题。

以编辑距离为例,它可以说是动态规划里最典型的二维状态转移题。状态定义是“A的前i个字符变成B的前j个字符需要的最少操作数”,转移方程看着简单,但真正理解它需要你自己推一遍:为什么增加一个字符是dp[i-1][j]+1、删除是dp[i][j-1]+1、替换是dp[i-1][j-1]+cost。这些不是背公式就能内化的,必须动手模拟一个小例子。

动态规划里还有一类很常见的问题叫“状态压缩”。比如二维状态只依赖上一行数据,就可以把二维数组压成一维数组。这在你后续处理大量数据时会经常用到,但面试高频考点里也常出现。平时做练习时我会刻意要求自己对能压缩的状态都试着压缩一遍,空间复杂度一下就从O(n * m)降到了O(m)。

2.5 图论与搜索:BFS、DFS、拓扑排序和并查集

图论这个模块在面试里的位置有点微妙,真正考到图的频率不如数组、树、动态规划那么高,但一旦考到就是送命题。这部分归档了岛屿问题(基本是DFS),单词接龙(典型BFS),课程表(拓扑排序),并查集相关题目。

岛屿类问题是最能体现DFS/BFS套路感的题目。核心模式就三步:遍历所有格子,遇到未访问的岛屿就把整个岛屿标记掉,数量加一。这里有个常见误区是不知道用什么数据结构记录“是否访问过”。有的题可以原地修改矩阵值,但面试时最好先问清楚能否修改输入,不行就用一个额外的visited数组,避免被面试官追问。

BFS还有一个非常重要的变体叫“多源BFS”,比如腐烂的橘子这道题。它的核心思想是找到给定的下一个时间点,多个源头同时向外扩散。很多人在写这类代码时没有先把所有源头一次性入队,而是一个个处理,导致扩散过程不是同步的,结果完全错误。

并查集题目在国内面试中出现频率越来越高,因为它能干净利落地解决“动态连通性”问题。并查集的模板代码其实很短,但要在面试现场写对,必须理解路径压缩和按秩合并这两处优化是干什么的:前者让树变矮,后者防止树退化成链。

2.6 回溯与排列组合:暴力搜索的艺术

回溯是另一种高频考点,它的本质就是DFS加上撤销操作。归档的典型题有全排列、子集、组合总和、N皇后、括号生成等。这类题的精髓是“递归之前做选择,递归之后撤销选择”。

我见过太多人把回溯题写成了无限递归,根本原因就是没有想清楚base case是什么。比如全排列,你的递归终止条件是当前排列长度等于总长度,那递归里的循环就只是为了穷举下一个位置放哪个数。如果不把这两个层次分开思考,代码就会乱。

组合总和和N皇后这类题还涉及剪枝优化。剪枝并不是花哨的高级操作,而是一种让递归少走冤枉路的朴素思想。比如组合总和里,如果你把数组先排序,当当前数大于剩余目标值时就可以直接break,而不是继续循环。这个优化在数据量大时能省下几倍的运行时间。

注意:回溯模板很简单,但“怎么剪枝”“怎么去重”才是区分代码好坏的关键。写完题目之后建议再想想:如果数据规模扩大100倍,这段代码还能跑吗?如果跑不了,问题出在哪里?

3. 核心模板与代码示例

3.1 手写一个滑动窗口的通用模板

滑动窗口是数组和字符串题型里非常实用的技巧,这里我分享一下这个项目里反复使用的一个模板,它是应对“子数组/子串”类问题的重要基础工具。

def sliding_window(s): n = len(s) window = {} left = 0 # 用于记录满足条件的窗口结果 ans = 0 for right in range(n): # 将 s[right] 加入窗口 window[s[right]] = window.get(s[right], 0) + 1 # 当窗口不满足题目条件时,收缩 left while 窗口不满足条件: # 移除 s[left] window[s[left]] -= 1 if window[s[left]] == 0: del window[s[left]] left += 1 # 此时窗口一定满足条件,更新答案 ans = max(ans, right - left + 1) return ans

这个模板的通用性很强,因为它把“条件判断”和“答案更新”的代码都留白,你自己去填。关键点是理解右指针负责扩展,左指针负责收缩,窗口的合法状态始终由条件驱动。真正写代码时,最容易错的是右侧新加入元素后窗口条件被破坏,却忘记收缩;还有一类是窗口需要记录两种以上信息时,条件判断写不清楚。建议多拿“无重复字符的最长子串”和“最小覆盖子串”这两道题来练熟这个模板,因为它们一个靠哈希计数判断重复,一个靠计数判断覆盖,正好覆盖了两种常见场景。

3.2 回溯算法的标准骨架

回溯也是面试里经常要手写模板的题型,我推荐把下面这个骨架背到肌肉记忆的程度:

def backtrack(path, choices): if 满足结束条件: 记录结果 return for choice in choices: 做选择 backtrack(新的path, 新的choices) 撤销选择

下面以全排列为例,看它怎么落地:

def permute(nums): result = [] n = len(nums) used = [False] * n path = [] def backtrack(): if len(path) == n: result.append(path[:]) return for i in range(n): if used[i]: continue used[i] = True path.append(nums[i]) backtrack() path.pop() used[i] = False backtrack() return result

核心习惯有两个:一是记录结果时必须用path[:]拷贝一份,而不是直接append(path),否则最终存进去的全是同一个对象的引用;二是剪枝逻辑要写在“做选择”之前,顺序不能错。回溯题做完之后可以试着在草稿纸上画出递归调用的状态树,这能帮你确认剪枝是否正确。

3.3 链表的递归反转模板

链表反转用递归解法能很自然地表达“递归是自底向上构建”的过程。这里给出参考模板:

def reverseList(head): if head is None or head.next is None: return head new_head = reverseList(head.next) head.next.next = head head.next = None return new_head

用生活化类比来理解:假设你有一列火车,递归到最后一节车厢后开始往回走,每走一节就把这节车厢掉头接到前一节后面,最后新的火车头就是原来的车尾。这个模板看着简单,但很多人第一次写会忘记把当前节点的next置空,导致链表里出现环。我当初也是被这个bug坑了整整一个晚上。

4. 常见问题与排查技巧实录

4.1 递归“无限循环”和栈溢出

很多同学的递归代码在本地一跑就Stack Overflow,第一反应是“我的递归终止条件写错了?”,但排查下来往往发现终止条件没错,错的是递归参数没有朝终止条件收敛。比如二叉树的深度计算,如果每次传入的节点写错了对象,就会在同样两个节点之间来回跳。

排查这类问题我的建议是:别上来就在本地大输入上跑,先加一个打印深度,看看递归调用栈最高到多少层就直接崩溃。一般来说递归过深不一定是逻辑错了,也可能是递推公式设计得不合适,导致状态空间太大。这时要回头审视自己是不是把多余状态也放进去了。

另外,Python等语言有递归层数限制,如果你深层递归一跑就红字报错,可以考虑自己加一个参数记录深度,这样即使不报错你也知道自己递归到了多少层。

提示:排查任何老出错的递归题,先在纸上手工跑一遍输入规模为2或3的用例,保证逻辑没问题再上机器,能省一半以上的调试时间。

4.2 二维数组索引越界怎么快速定位

做岛屿类、网格类DFS/BFS题目时,最常见的报错就是IndexError。这类错误很多情况下不是单个坐标算错,而是你在“访问邻居”的时候越界。项目里我总结了专门用于防越界的写法,核心思路是先判断坐标是否在矩阵范围内,再决定是否访问。

directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] for dx, dy in directions: nx, ny = x + dx, y + dy if 0 <= nx < rows and 0 <= ny < cols: # 访问 (nx, ny)

凡是二维网格题,我一律建议把所有邻居扩张逻辑集中在一个地方,不要在每个递归分支里单独写越界判断,这样不仅代码整洁,排查问题也方便不少。

4.3 动态规划的状态初始化错误

动态规划里最常见的Bug不是转移方程写错,而是初始化写错。拿二维DP来说,很多人能写出状态转移,但第一行和第一列的初始值拍脑袋就填了,导致整个表错了一半。最典型的就是求最小路径和时,网格第一行只能从左过来,第一列只能从上过来,这两个方向必须单独初始化,不能用统一的转移逻辑。

还有一种情况是把“非法状态”初始化为0,但0在某些题目里是合法的答案,导致状态覆盖出错误。比如求最长递增子序列长度时,dp数组的非法初始态就应该是1而不是0,因为单个元素至少能构成一个长度为1的子序列。初始化之前建议先问自己:这个状态的“最小有效值”是多少?它和“无效值”怎么区分?

4.4 写完代码老超时?复杂度分析不能只靠感觉

很多人的代码在力扣上跑不过全部用例,一看就是时间复杂度太高。但你说他也不知道该优化哪里,因为“感觉每个循环都是必须的”。我比较推荐一个习惯:每道题解完之后,强制自己用大O符号写出时间复杂度和空间复杂度,然后对照数据范围检查是否合理。

这个习惯特别有用。比如一道题的数据范围是10的5次方,那O(n²)的解法基本就是超时预定,此时就要考虑怎么优化到O(n log n)或者O(n)。实时监控自己的复杂度层级,比刷题数量本身更重要,因为面试官在白板环节一定会追问“你的算法复杂度是多少”,你必须能回答得出。

4.5 手写代码时变量命名混乱导致低级Bug

新手写算法题时还有一类非常隐蔽的问题,就是变量命名混乱。比如left、l、low、lo在同一个函数里混用,一旦逻辑变复杂,自己都搞不清哪个变量维护的是哪个区间。我的建议是即使算法题这种短代码,也尽量用语义化的命名,比如window_left、window_right、node、curr、prev。

变量名太短不一定会导致答案错误,但一定会导致你排查时间变长,面试时看起来特别不专业。我在模拟面试中见过不少候选人解题思路完全正确,但指着代码里的tmp半天说不清它代表什么,这种印象分损失其实很大。

5. 刷题工作流与长期复盘建议

5.1 我用什么工具管理这些算法题

我自己维护这种算法题合集的时候,工具选得不复杂,但非常顺手。第一是VS Code,配合一个LeetCode插件,可以直接在本地拉题、写代码、跑测试;第二是一个简单的本地文件夹结构,按数据结构和算法思想分类存放题解;第三是一个Markdown笔记文件,记录每道题的“坑点”和“复盘提醒”。

这样的工具组合比直接依赖在线题库的收藏夹更有掌控感,因为本地资料能长期积累,不会随着账号失效或被平台改版而丢失。有一点要特别建议:每道题解之后,写一段两到三行的简短总结,包含题型归类、核心思路、复杂度,以及“我第一次做错的地方”。这些总结才是你复盘的宝贵资料,而不是那堆已经有的代码。

5.2 如何复盘才能避免“刷了就忘”

很多人刷了几百道题之后面对新题依然没思路,最大的问题在于复盘方式不对,只是机械地“看题-写题-对答案-下一题”,大脑里根本没有建立知识索引。这里分享一个我自己坚持了很久的方法:每周挑三到四道之前做过的题,不参考任何材料,从零开始重新实现一遍。

请注意,这里的复现不是默写代码,而是要完整重现自己的思考过程:这题属于什么类型?为什么用这个数据结构?状态怎么定义?转移方程怎么推导?边界条件有哪些?如果直接能顺利复现,这道题才算真正内化。如果卡壳了,就去看自己的复盘笔记,找找当初卡在哪儿,而不是重新看题解。

5.3 面试前一周的冲刺策略

面试前一周不适合再去碰新题,而是要切换到“实战演练模式”。我的做法是模拟面试环境:拉一个随机标签的题目,在白板上用笔和纸或者Markdown编辑器手写代码,限定在30分钟内完成。这个过程重点锻炼的是“时间分配能力”:前5分钟必须把思路想清楚并想好复杂度,中间20分钟写代码,最后5分钟自查边界。

如果你手头这个“部分算法题”项目已经整理好了高频题和易错题,面试前几天就只看这两类,反复看自己总结的复盘笔记就够了。不用临阵磨枪去刷新题,那样反而会打乱已经建立起来的题型地图和信心。

5.4 这个项目后续还能怎么扩展

“部分算法题”这个项目做完了并不代表结束,它是个活的项目。你可以持续把平时工作中遇到的有意思的算法题加进对应分类;也可以按题目难度给每道题打上难度标签,形成一条从入门到进阶的升级路线。更进一步,可以为每道题补充“一题多解”的对比解析,把多种解法的复杂度、编码难度、面试表现放在一起对比。

我个人实测下来,做完这些扩展之后,我再面对任何一道新的算法题时,每隔几秒就能在脑内定位它的题型归属,然后快速套出对应范式。这种感觉遥想一下就像你在一个乱糟糟的工具箱里翻东西,后来把每个工具挂了标签、放了固定位置,拿什么都是顺手的事。

最后再补充一句:算法刷题是一条需要耐住寂寞的长路,技巧可以学,模板可以背,但真正拉开差距的还是你对自己的思考过程有没有足够细致和诚实的复盘。这个项目承载的正是我对自己这些思考的沉淀,也希望它对你的刷题方式能有点启发。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 7:20:30

Ubuntu开机自启脚本的正确姿势:systemd启动阶段精准控制

1. 项目概述&#xff1a;为什么 Ubuntu 开机自动执行脚本不是“配个 crontab -e 就完事”的事“ubuntu 开机自动执行脚本”——这行字在某高校实验室的 Linux 入门答疑群里&#xff0c;平均每周被问 7 次&#xff1b;在某外包公司运维交接文档里&#xff0c;是新同事踩坑率排名…

作者头像 李华
网站建设 2026/10/13 7:20:28

VMware 【13】设置非永久磁盘,验证关机后的数据变化

&#x1f525; 个人主页&#xff1a;杨利杰YJlio ❄️ 个人专栏&#xff1a;《Windows 疑难杂症与工单复盘案例库》 《Sysinternals实战教程》 《WINDOWS教程》 《Windows PowerShell 实战》 《IOS插件分析测试》 《超简单&#xff1a;用Python让Excel飞起来》 &am…

作者头像 李华
网站建设 2026/10/13 7:19:09

Kubernetes核心组件详解:Pod、Controller与Service实战

在Kubernetes里摸爬滚打了几年之后&#xff0c;我越来越觉得&#xff0c;理解核心组件比背一堆命令管用得多。很多刚接触K8s的朋友一上来就去啃YAML、记kubectl参数&#xff0c;结果遇到问题还是懵圈。原因很简单&#xff0c;他们没搞明白Pod、Controller、Service这三样东西在…

作者头像 李华
网站建设 2026/10/13 7:19:07

SpringBoot+Vue+MyBatis实战:企业级民俗网管理系统开发全解析

1. 项目概述与核心需求拆解1.1 这个项目到底在解决什么问题做民俗文化类网站&#xff0c;最尴尬的不是没内容&#xff0c;而是内容管理方式还停留在“改代码、传服务器”的阶段。早些年我接过不少文化类站点&#xff0c;很多单位的民俗资料库就是一个静态页面加几个Excel表格&a…

作者头像 李华
网站建设 2026/10/13 7:18:37

网络安全从业者深造高校研究生:在职回炉的机遇与备考路径

站在一名在网安行业摸爬滚打多年的从业者角度&#xff0c;看到“公开征集45名网络安全从业者深造一流高校研究生&#xff0c;在岗人员优先”这类消息&#xff0c;第一反应不是急着转发&#xff0c;而是先冷静拆解一下背后的信号。行业里很多人工作三五年后都会遇到一个共同的瓶…

作者头像 李华
网站建设 2026/10/13 7:17:55

萤石开放平台音视频协议选型实战:从RTMP到WebRTC的决策指南

做萤石开放平台音视频对接&#xff0c;我估计很多人跟我一开始一样&#xff0c;拿到需求和文档先不是高兴&#xff0c;而是发懵。一堆协议缩写堆在眼前&#xff1a;RTMP、HLS、RTSP、FLV、WebRTC&#xff0c;还有各种播放地址、鉴权参数、拉流域名&#xff0c;到底该用哪个接&a…

作者头像 李华