最近在整理大学院笔试的复习资料,把线性代数和数据结构这两门课重新刷了一遍。越刷越觉得,这类笔试和本科期末考试完全是两个物种:期末考试考“你学过没有”,笔试题考“你能不能在这个规定时间内把题做对”。尤其是线性代数里的证明题和数据结构里的手写代码题,只看不练等于白看,偏偏这两块又是大部分人的薄弱区。
这篇东西不是教材的复述,是我自己从“看网课觉得都会”到“上考场能稳定拿分”这段时间里,针对线性代数和数据结构第一轮复习总结出来的一套做法。内容包括高频考点怎么拆、题目怎么练、草稿怎么打、代码题怎么背模板,以及最容易踩的坑。适合正在准备研究生入学笔试、大学院入试,或者单纯想把这俩基础课夯实的人。如果你已经进入第二轮刷真题阶段,里面查漏补缺的部分也可以直接对照用。
1. 先说清楚:这类笔试到底在考什么
很多人复习大学院笔试容易犯一个错误,就是把过去本科的教材从头到尾又啃一遍。我没说教材不重要,但如果目标是笔试拿分,你得先搞清楚出题人想要什么样的能力。
拿线性代数来说,大学院笔试题普遍不考“算一个四阶行列式”这种纯计算,而是喜欢考“带参数的行列式等于零时,矩阵的秩会发生什么变化”“给定一个二次型,判断它是否正定并说明理由”。这种题的背后考的是你能不能把行列式、秩、特征值、二次型这几块内容串起来。单独背任何一个公式都答不了题。
数据结构就更明显了。笔试里的算法题通常不允许你用IDE调试,就是白纸黑字手写代码,或者给你一段伪代码让你分析复杂度。这时候你光知道“快排的思路是分治”远远不够,你得能在十分钟内写出一个不出错的分割函数,还要能解释为什么最坏情况下是O(n²)。说白了,数据结构笔试考的是“代码熟练度 + 概念精确度”的组合,缺一不可。
还有一个容易被忽略的点:时间分配。我以前做模拟题喜欢死磕一道证明题,结果后面数据结构的代码题只写了一半。后来我调整了策略——按照分值分配时间,比如线性代数部分规定自己在60分钟内完成,超过5分钟还理不清思路就先跳过,最后剩15分钟回来写关键步骤。实践证明,大多数笔试题的区分度本来就不在“你是不是全都会”,而在“你有没有在有限时间里把会做的都做对”。
这套思路贯穿我下面所有复习内容:先建知识框架,再练高频题型,最后用模拟考来校准节奏。
2. 线性代数第一轮:我不按教材顺序复习
很多人复习线性代数是从行列式开始,然后矩阵、向量、方程组、特征值一路往下走。这个顺序本身没问题,但我第一轮复习的时候试过另一种安排,效率更高:先花半天时间把“线性变换”和“基与维数”这两个概念彻底搞明白,再回头看行列式和矩阵。原因很简单,行列式的几何意义就是线性变换对体积的伸缩系数,你一旦接受这个设定,很多“为什么行列式为零矩阵就不可逆”“为什么转置不改变行列式”之类的性质就不再需要死记。
第一轮复习我给自己定的指标不是“看完多少页书”,而是“能不能合上书把每个章节的考点结构画出来”。比如矩阵这块,核心就三件事:运算规则、逆矩阵、分块矩阵。运算规则里要特别注意矩阵乘法不满足交换律,这一个点就能衍生出一堆选择题陷阱。逆矩阵要熟练掌握伴随矩阵法和初等变换法,但不能只满足于会算,还得知道“可逆矩阵的秩等于阶数”这个底层逻辑。分块矩阵看似偏应用,实际上很多高阶题用它来简化计算,尤其是对角线分块。
2.1 行列式和矩阵:计算是底线,但更重要的是“怎么用”
行列式这部分我最想强调的是性质,而不是展开公式。很多同学一上来就背“按行展开”的公式,结果遇到带字母的行列式就懵。其实大学院笔试里纯数字的大行列式计算很少见,更多的是给你一个抽象行列式,让你用性质把它化成简单形式。我当时给自己定了一个原则:每一步初等变换都必须写出“用的哪条性质”,如果写不出来,说明这一步是蒙的。
举个我反复练的题型:已知A是三阶矩阵,|A| = 2,求|2A⁻¹ + A*|这类。这题看着吓人,实际上你只要掌握三件事就能解:|kA| = kⁿ|A|(n是阶数)、A* = |A|A⁻¹、逆矩阵的行列式是原矩阵行列式的倒数。把这些关系套进去,三步就能算完。我会在旁边醒目标注:A*和A⁻¹的关系是这个题型的核心,以后再遇到伴随矩阵,第一反应应该是把它换成A⁻¹,而不是傻乎乎去求每个代数余子式。
矩阵的秩是另一个大考点。判断秩的方法很多,但在笔试里最实用的是“通过初等行变换化成行阶梯形,非零行数就是秩”。这句话说起来简单,实际操作经常出错的地方是:有人只允许行变换,结果看到需要列交换时就不敢动了。这里要澄清一下,求秩的时候行变换和列变换都可以用,因为初等变换不改变秩,这一点和求逆矩阵时“只能行变换”不同。
2.2 秩、特征值、二次型:高频题的三个突破口
秩的概念是连接线性方程组解的结构和向量组相关性的桥梁。复习到这个地方,我建议你做一个对照表,把“矩阵的秩”和“向量组的秩”用不同维度写清楚:矩阵的秩是从行或列向量组的角度看的,行秩等于列秩等于矩阵的秩,这个结论本身就是一个常考小证明。考试时遇到“A是m×n矩阵,r(A) < n,说明Ax = 0有非零解”这类判断题,本质上就在考你能不能把这个结论反过来用。
特征值这块是线性代数里题型的“集火区”。求特征值本身不难,难的是特征值和秩、行列式、迹之间的牵扯。比如“实对称矩阵不同特征值对应的特征向量正交”这个结论,几乎每年都有学校会考。再比如“A相似于对角阵”的充要条件是有n个线性无关的特征向量,很多人只记住了这个条件,却不知道实际操作时该怎么做。我的笨办法是:遇到抽象矩阵判断是否可对角化时,先算特征值的重数,再看每个重根对应的特征向量维数是否等于重数,不等就说明不能对角化。
二次型其实就是实对称矩阵研究的应用延伸。你一旦理解“二次型对应一个实对称矩阵”,那正定判断就变成“所有顺序主子式大于零”或“所有特征值大于零”,看你更擅长哪种路数。角度不同,做题速度差别很大。比如给你一个三元二次型,问你它在什么条件下正定,用顺序主子式通常最直接。但如果题目已经暗示特征值相关,比如“已知A的特征值为1、2、3”,那就不用再展开成平方和了,直接判定就行。
2.3 计算规范:草稿纸上的习惯决定对不对
线性代数计算密集,草稿纸上的习惯直接决定准确率。我见过太多人不是不会做,而是草稿写得乱七八糟,符号抄错、负号漏掉,最后答案错得很冤。
我的建议是:从第一轮开始就养成“行列对齐 + 每步编号”的打草稿习惯。初等变换的每一步都在草稿纸上标注行号,比如“r₂ - 2r₁”写清楚是把第二行减去第一行的2倍,而不是反过来。别小看这个习惯,它能帮你快速回查错误。还有,数字不潦草,尤其是0和6、1和7这种容易看混的组合,在矩阵里一旦看错,后续所有计算全废。
另一个很实用的点是:能心算的步骤不要省,但关键步骤不要跳。比如两三阶行列式的数值可以直接展开,但伴随矩阵、逆矩阵这种多步操作,每一步都写出来。你可能觉得这样慢,但在考试紧张状态下,不跳步反而比跳步快,因为不用回头检查。
3. 数据结构第一轮:代码题靠背模板不丢人
数据结构这门课,本科上课的时候教材用得比较杂,严蔚敏版、王道版、还有各种学校自编教材都有。但不管哪本教材,笔试考核的核心归纳起来其实很集中:线性结构、树与二叉树、图、查找和排序这五大块。第一轮复习的重点,是把每块里面的“骨架题”吃透。
很多人对“背模板”有误解,觉得学算法靠背模板是走捷径。我的看法不一样:如果你在考场上是现场想链表反转的递归逻辑,那你大概率写不完卷子。真正的高手是把常见题型练成条件反射——拿到题知道它的考点归属,直接调用对应模板,然后再根据题目微调。这和运动员练到肌肉记忆是一个道理。
但注意我说的是“背模板”,不是“背答案”。一个模板你至少要能回答四个问题:这个算法解决什么问题?它的时间复杂度为什么是这个量级?它的关键边界条件是什么?如果输入条件变化,模板哪里需要改?四个问题答得上,才算真正掌握了它。
3.1 线性表、栈和队列:先把手写基本功练到条件反射
线性表是所有数据结构的地基。笔试里最常见的不是让你实现一个完整的顺序表,而是手写单链表的插入、删除、反转。我复习前期每天都会花十五分钟在白纸上写一遍“单链表反转”的迭代实现,要求自己三个约束:不能借助额外数组空间、指针操作顺序不能乱、循环终止条件不能错。这道题写熟了以后,很多链表的变种题都会轻松很多。
再强调一次,指针修改顺序是链表题的高频翻车点。比如删除节点p的后继节点,应该先让p的next指向p的next->next,再释放那个被删除的节点。如果你先把释放操作做了,后面就没法访问next了。这种顺序问题,代码水平再高的人也可能在考场手滑,所以必须靠平时反复默写来规避。
栈和队列的考点比较集中,常见的是:用两个栈模拟队列、括号匹配、中缀表达式转后缀、循环队列的队空队满判断。我建议你用“操作视角”去理解栈和队列的区别,不要只背“先进后出”“先进先出”这八个字。比如括号匹配问题,它的核心思路就是“遇到左括号入栈,遇到右括号弹出栈顶检查是否配对”,这个流程其实是在活用栈的“后进先出”特性来匹配最近的左括号。
3.2 树与二叉树:递归是核心,非递归是加分项
二叉树是数据结构的半壁江山。笔试题从遍历到重建、从最近公共祖先到AVL旋转,都是以二叉树为载体的。复习树这一章,我建议你先透彻理解递归遍历。前序、中序、后序遍历的递归写法只有几行,但你要能画出递归调用的栈帧过程,理解每个节点何时被访问。很多人写递归遍历没错,但遇到“已知中序+前序,重建二叉树”就懵了,原因就是没理解遍历序列的本质。
非递归遍历是很多学校的进阶考点。我记得自己第一次手写非递归中序遍历时,总是忘记“出栈后转向右子树”这一步。后来我形成了一套口诀:沿着左子树一路入栈,走到空就出栈访问,然后转向右子树继续。这套口诀后来我每次写代码前都默念一遍,准确率提升明显。如果你是冲刺高分,非递归前序和中序务必掌握,后序可以视精力而定,但层次遍历不应该丢分。
树的另一部分考点是BST和AVL。BST的查找、插入、删除要能默写,而且要特别注意前驱和后继节点的概念。AVL的四种旋转(LL、RR、LR、RL)我记了很多遍才真正搞懂,我的经验是不要死背旋转类型,而是抓住两个关键:哪个节点失衡了、失衡路径是往左还是往右。顺着这个思路去推,旋转方式自己就能画出来。
3.3 图、排序和查找:考点密度最高的三块
图的问题是数据结构里最容易补全知识广度的一块。DFS和BFS必须能默写,拓扑排序也要会手动模拟和代码实现。最短路径里Dijkstra算法是重点,它的核心思想是“贪心”,每轮找当前距离源点最近且未被访问的节点,用它去松弛邻居。我在复习时用一个小例子反复手推,推了三遍以后把算法流程完整背下来。
生成树那边的Prim和Kruskal是容易混淆的一对。我的记忆锚点是:Prim是“加点法”,适合稠密图;Kruskal是“加边法”,适合稀疏图。考试时不一定让你写完整代码,但至少会给一个图让你手动模拟,这种题稳拿分的唯一办法就是平时亲手画过几遍。
排序算法是期末和笔试的双重重点。我复习时画了一张大表,把七种常用排序(插入、希尔、冒泡、快排、简单选择、堆排、归并、基数)的稳定性、最好/平均/最坏复杂度、空间复杂度全部整理出来。这张表的重要性怎么强调都不为过,因为每年都有大量选择题和判断题在考这些点。时间复杂度的记忆有个小技巧:平均情况下,快排、堆排、归并三家是O(nlogn),其余简单排序大多是O(n²)。稳定排序要记住两个例外:直接插入和冒泡是稳定的,简单选择和快排不稳定,堆排不稳定。
查找部分的核心是二分查找和散列表。二分查找虽然代码简单,但边界条件特别容易错。我习惯统一用“left = 0, right = n - 1, while (left <= right)”这套闭区间模板,写熟后不要再换,否则考试时容易乱。散列表重点掌握哈希函数构造和冲突处理,线性探测法和链地址法都要能模拟整个过程。
4. 两科交叉复习的时间安排(附个人排期)
第一轮复习阶段,我遇到的最大问题不是学不会,而是时间安排不合理。有一段时间我连续一整个星期只刷线性代数,数据结构完全没碰,结果回过头来写链表反转都手生。后来我调整了策略:每天两科都接触,但规定不同侧重。
4.1 一天两科还是隔天轮换
如果你是全天复习,我建议上午安排线性代数,下午安排数据结构,晚上花二十分钟回顾当天的错题。为什么这样分?因为线性代数需要清醒的头脑去处理复杂的符号运算,安排在精力最好的时段比较合适;数据结构偏重理解和手写代码,下午精神状态有所下降但依然可以完成,晚上回顾也方便。如果你是碎片化时间复习,那就别勉强“必须凑一整块时间”,用番茄钟把一个考点拆成25分钟的单元也可以,但一天内至少要保证两科都能过一遍,保持手感。
4.2 刷题量的控制与复盘节奏
第一轮复习不要太追求数量。我当时给自己定的量是:线性代数每天12~15道练习题,数据结构每天5~6道算法题,但每道题做完后必须复盘。复盘不是“看一眼答案对了就过”,而是要把这题的题型、用到的定理、我的易错点、如果换一种问法该怎么办这四件事写在错题本上。
这个错题本我不是按时间记的,而是按考点分类。比如线性代数分“行列式计算”“矩阵运算”“秩与方程组”“特征值”“二次型”五类;数据结构分“线性表”“栈与队列”“树”“图”“查找”“排序”六类。分类的好处是,第二轮复习的时候你可以直接对着某个薄弱分类集中刷题,而不需要翻遍整本笔记找某一个知识点的错题。
5. 容易出错的操作细节和应对速查
复习到后期,我把自己在两科里反复犯的错误整理成了一份“易错清单”。这里挑一些比较有代表性的分享出来,你可以拿它当自查表:
5.1 线性代数高频失分点
- 求行列式时进行行变换和列变换混用,导致符号判断错误。解决方式:只进行行倍乘和行倍加时不会改变行列式的值,但如果交换了两行,记得加负号。
- 计算逆矩阵时误写成伴随矩阵除以原矩阵行列式的倒数。正确关系:A⁻¹ = A*/|A|,千万不要把位置调反。
- 判断矩阵是否可逆时,很多人只检查行列式是否为零,却忘了验证矩阵是否方阵。非方阵连“可逆”的定义都不成立。
- 实对称矩阵对角化时,特征向量要正交化、单位化,但普通矩阵不需要单位化。这里很多人容易搞混,要分清楚。
5.2 数据结构高频失分点
- 链表操作中指针的赋值顺序错了。最典型的是反转链表时,先修改当前节点的next导致后续节点丢失。解决办法:用临时指针保留下一个节点再修改next。
- 循环队列判断“队空”和“队满”时条件混淆。通常约定:队空是rear == front,队满是(rear + 1) % maxSize == front。这个约定失去一个存储位置,但能简化判断,笔试里最为常见。
- 二叉树递归遍历的返回值搞错。如果题目让“求二叉树所有节点数”,递归终止条件不是return NULL,而是return 0。
- 排序里“稳定”和“不稳定”记忆错乱。我常用的锚是:选择排序和快排不稳定,堆排不稳定,其他常见排序里插入和冒泡稳定,归并稳定,基数排序本身稳定(按主关键字排序时稳定但需要看具体实现)。
- Dijkstra算法不能处理负权边,Floyd可以但复杂度高。题目如果出现负权边,不要傻乎乎直接套Dijkstra,可以考虑Bellman-Ford或者题目是否禁止了负权边。
5.3 我的“错误记录本”怎么用
先说结论:错误记录本不应该是把错题抄一遍再写上正确答案就行了。我见过很多人做了厚厚一本错题集却收获有限,原因是他们记录的是“答案”,不是“错误原因”。有一段时间我记录一道线性代数错题时只写“伴随矩阵公式用反”,后来复习时根本不知道当时为什么会用反。后来改成要求自己必须补一段话:当时我脑子里是怎么想的?为什么会产生这个错误想法?正确的理解应该是什么?这样记下来的东西才有复盘的杀伤力。
我还会给自己的错题标记优先级。第一优先级:两科里重复犯的错。这种错必须在一周内重新做一遍原题和同类变式。第二优先级:会做但做错的题,大概率是草稿或者细节问题,考前一周用来警醒自己就行。第三优先级:完全不会的题,代表知识盲区,要回到教材或者网课把基础概念重新看一遍。
数据结构部分我还会在错题本上画出当时写错的代码和改对的代码并排对照,用红笔标出差异行。考前翻一遍这部分,比我重新做十道题性价比更高,因为我能在很短时间里面看到自己最容易在哪个边界条件上翻车,比如二分查找的right边界是n还是n-1、快排的partition循环条件是该写 low < high 还是 low <= high。这种细节如果没在错题本里留下痕迹,考场上大概率还会再错一次。
最后再分享一个小技巧:第一轮复习结束后,我给自己做了一次全真模拟。用目标院校的往年真题,严格按照考试时间,不查资料、不中途休息,模拟完当晚就分析哪些题是“完全会做但时间不够”、哪些是“看着眼熟但写不出来”的。这个分类比单纯看分数有用得多。前者要练速度,后者要回去补理解。等你把这两块的区分度摸清楚,第二轮的复习计划自然就有了方向。