
最近这段时间有好多读者在后台问我机试到底怎么准备问得最多的一句话就是“刷题刷了不少一到机试还是卡住到底差在哪”。今天是周末我抽空把这几年参加各类机试、以及帮别人复盘机试真题的经验整理成一份比较完整的刷题攻略从备考思路到具体实施从高频考点到避坑方法都聊透。文章会比较长但对准备华为od机试、北航软院机试、浙软机试或者互联网公司校招机试的人应该都有参考价值。1. 机试到底在考什么别把力气使错方向1.1 机试不是算法竞赛别用竞赛思维去准备很多人一提机试上来就抱着《算法导论》啃或者把竞赛题库当主战场这种做法不能说完全没用但性价比真的很低。大多数机试的本质不是选拔数学天才而是考察一个人在限时、有压力的环境下能不能用计算机解决实际问题的基本能力。它的难度区间通常集中在LeetCode的简单到中等题偶尔会出现接近困难档的题目但比例很低而且往往有面试官故意设置的“送分题”保底。换句话说机试更像是一场“工程能力的基础体检”而不是“智商碾压的竞技场”。你不需要精通网络流、后缀自动机、仙人掌图优化这些竞赛进阶内容你需要的是把常用的数据结构、基本的算法套路、严谨的边界处理练到形成肌肉记忆保证在考场上一次通过率足够高。我记得有次帮一个人保财险软件机试的考生做复盘他自嘲说刷了大半年竞赛题结果考试时被一道字符串日期差值题卡了四十分钟不是不会做是处理闰年和输入格式时反复出问题最后代码改到面目全非才勉强通过。这就是典型的备考方向跑偏练了一堆用不上的高难技巧却忽略了机试真正的得分点。1.2 不同机试的差异盘点看清你的“对手”虽然都叫机试但不同类型的机试侧重点差异很大。我按常见的几类场景做个梳理方便你对号入座。互联网公司校招机试比如华为的od机试特点是题量大、时间紧、平台统一通常以ACM模式考察需要自己处理输入输出。华为od机试真题有比较高的重复率题库范围相对明确很多在牛客网和力扣上能找到原题或变体。这类机试的策略重点是“刷透经典题型熟悉ACM模式下各种输入输出写法”。高校保研机试比如北航软院机试、浙软机试这两年在保研圈权重越来越高。北航软院机试通常会有几道题从简单到难递进第一题往往是签到题后面开始上难度。浙软机试的特点同样注重基础数据结构和算法且有一些题目在风格上偏向校赛入门难度但不会到竞赛级。备考这类机试时建议多关注往年经验帖把目标院校的题库风格研究透比盲刷1000道力扣更有效。国企和传统软件企业机试比如人保财险软件机试这类场景难度相对温和更看重基础的C语言功底、逻辑正确性和代码风格。很多人因为轻视这类机试结果在细节上翻车比如函数命名随意、不写注释、边界条件考虑不周被阅卷系统判定扣分。C语言专项机试部分学校和单位会单独设置C语言机试比如东北师范大学的计算机相关考核这类机试重点考指针、结构体、字符串处理、内存管理。备考时要特别强化C语言特有的“坑”比如字符串末尾的\0、指针的越界访问、scanf和gets的混用问题。1.3 刷题前先明确目标场景再做计划我在后台收到过很多类似“我准备北航软院机试现在开始刷力扣该按什么顺序刷”的问题。我的建议是先别急着刷先花两三天时间做三件事。第一查清楚你目标机试的平台模式。是ACM模式自己写输入输出还是核心代码模式只写函数体如果是ACM模式那你还得针对性地练习各类输入输出的“模板代码”。第二找过往真题或者靠谱的题库。华为od机试真题在多个平台有整理北航软院机试、浙软机试往年题在一些论坛和经验帖中也能找到回忆版。真题的参考价值永远是最高优先级。第三给自己做个摸底测试。模拟考场环境限时2小时做一套目标类型的题看看自己目前的起点在哪里。这个摸底成绩决定了后续刷题的侧重如果基础题都能稳定做出来可以适当增加中高难度比例如果签到题都费劲那就老老实实回归基础先别碰难题。2. 刷题怎么规划题型分层与时间安排2.1 题型优先级排序明确什么先刷什么后刷机试题型虽然五花八门但核心考点是有规律的。我根据自己的经验把常见机试题型按优先级排了个序这个顺序基本覆盖了大多数本科和硕士阶段计算机类机试的高频范围。P0级别必会基本每场都考数组与链表的基础操作、字符串处理子串、分割、反转、去重、排序与自定义排序、哈希表应用、双指针。为什么这些是必会因为它们是最基础的数据组织方式和暴力优化手段几乎所有复杂题都能分解成这些基础操作的组合。P1级别高频出现需要熟练掌握模板栈与队列单调栈、优先队列、滑动窗口、DFS/BFS搜索、二叉树遍历与基础递归、动态规划基础背包、最长子序列、最大子数组、贪心思想。这类题是机试拉开差距的主要区域也是“中等难度题”的主体。P2级别视目标而定性价比偏低图论进阶最短路、最小生成树、并查集、线段树/树状数组、字符串匹配KMP、状态压缩DP。这部分内容不是必须的除非你的目标机试明确考过这类题否则前期完全不用碰后期有余力再补充。我个人建议把刷题资源的分配控制在P0占40%、P1占45%、P2占15%左右。这样既保证了基础题的“稳”又有能力冲刺中等偏上的题目。2.2 刷题数量的科学规划不是越多越好很多备考者迷信“刷满500题就能稳过”这个说法只能说方向对但不精准。我带过的人里有人刷了100多题就过了华为od机试也有人刷了800多题依然挂在一道中等题上原因就在于后者陷入了“无效刷题”的循环。所谓有效刷题是指每道题都能做到三步独立思路、完整实现、复盘总结。如果一道题你只是看了题解然后照着默写一遍那这道题在考试中对你的帮助几乎为零。真正有效的刷题数量标准是目标机试难度偏低国企类、部分C语言机试150到250题足够重点覆盖P0和基础P1题型反复巩固至少两轮。目标机试为互联网公司od类或保研类300到400题比较稳妥其中至少三分之一要二刷甚至三刷确保“看见题就知道思路”的程度。如果备考时间只有一个月优先保证高频题型精刷而不是追求数量。一天刷10道简单题不如一天深挖2道中等题。2.3 建立错题和题型的归档方法别让题目刷了就忘这里分享一个很多经验帖不会细说的方法整理自己的“算法题归档”。我自己的做法是用一个表格或笔记软件来管理核心字段是“题目编号、题目标题、考点类型、难度、首次是否AC、二次是否AC、错误点记录”。这看起来有点繁琐但实际收益很高。比如我整理错题时会专门记录自己当时的错误原因是边界没处理好还是思路偏了还是某个API用反了。到了考前冲刺阶段我基本不再刷新题而是只看这个归档里的“错误点记录”和“二次是否AC”列只看自己最容易翻车的点。还有一个很实用的做法每道题在AC之后强迫自己想一下“如果题目改一个条件我现在的代码还能不能过”。比如一道求连续子数组最大和的题如果把“连续”改成“不连续”把“和”改成“乘积”把“数组”改成“环形数组”思路会发生什么变化。这种延伸思考能让一道题发挥三道题的训练效果。3. 高频考点的拆解与实操要点3.1 输入输出处理最容易被忽略的分数杀手我见过太多人在机试里因为输入输出处理不当而丢分而且丢得特别冤枉。这里说的不是scanf和printf这种基础语法而是ACM模式下的输入读取策略。先说一个最常见的坑循环读入。有些题目没有明确告诉你输入有几行只说了“输入多组测试数据”。这时候如果你用固定次数的循环去读大概率会漏读或者读到空对象。正确的做法是用文件结束符判断循环条件。C语言里用while(scanf(%d, n) ! EOF)C用while(cin n)Java用while(scanner.hasNextInt())Python用while True: try: ... except EOFError: break的模式。再说第二个常见的坑读取字符串时的空白符处理。C语言里scanf遇到空格会停止如果你要读取一行含空格的字符串就不能直接用scanf(%s)得考虑用fgets或者gets在支持的环境下或者用scanf(%[^\n])这种格式。这个细节在字符串处理类题目中特别致命比如一道输入一行包含多个空格分隔的日期时间然后要求解析的题很多C语言考生就在这里翻车。还有一个更隐蔽的问题大数据量输入时的效率。C用cin和cout时如果题目数据量达到百万级别不考虑ios::sync_with_stdio(false)和cin.tie(nullptr)两行加速代码可能被卡超时。Java的Scanner在处理大量输入时也偏慢可以考虑用BufferedReader加StringTokenizer或者维护一个自定义的快读模板。Python则需要注意别在循环里用input()逐行读大数组应该一次性sys.stdin.read().split()取出来再处理。3.2 字符串与数组处理机试里的“基础中的基础”字符串题在机试中出现的频率高到离谱华为od机试真题里几乎每场都有至少一道。字符串题为什么受出题人欢迎因为它们的输入输出天然需要自己解析天然适合ACM模式而且解法能覆盖多种算法思路。字符串的基础操作里有几个点值得反复练习子串搜索与截取、字符频率统计、字符串翻转、回文判断、字符串与整数的互转。这些操作一定要熟到不用想语法因为到了考场上人的大脑在紧张状态下处理不熟悉的API是会当机的。数组处理方面最核心的是下标边界和循环不变式。比如二分查找我见过的翻车案例里十有八九是while(left right)和while(left right)用混了或者mid (left right) / 2在极端情况下溢出了。在Java里int mid left (right - left) / 2才是稳妥写法。再比如数组轮转、合并两个有序数组、去除重复元素这类题每个都有特定套路建议当做模板题来背。我特别想提醒C语言考生数组题里“下标从0还是从1开始”是个容易集体翻车的地方。如果你习惯1-based但题目要求0-based或者反过来一定要在草稿纸上先画清楚对应关系再动手写代码。这种错误编译器不会报错逻辑跑起来却莫名奇妙错调试时间极长。3.3 哈希表、双指针、滑动窗口中等题的三大支柱如果机试里的简单题是“送分题”中等题就是“决胜题”。在所有中等题里哈希表、双指针、滑动窗口这三类技巧的出场率极高而且相互之间经常搭配使用。哈希表的核心思想是“空间换时间”把查找从O(n)降到O(1)。最经典的是“两数之和”暴力法是两层循环哈希表法是一遍遍历一遍查。机试中很多题都能往哈希表上靠统计出现次数、找重复元素、判断两个集合的交集、字符串分组等。用哈希表时注意key的类型定义C里如果是自定义结构体需要重写比较和哈希函数这在考场上很容易折腾人尽量优先用整数或字符串做key。双指针的核心是“利用有序性减少无谓的遍历”最常见的应用场景是有序数组的两数之和、三数之和、反转数组、移除指定元素。写双指针时一个容易忽略的点是左右指针的移动条件所有移动分支必须保证最终能相遇否则就会死循环。机试超时排查时一个常见原因就是双指针的移动条件写反了。滑动窗口本质上是双指针的升级版用于处理“连续子数组/子串”的最优解问题例如寻找最长无重复字符子串、最小覆盖子串、定长子数组均值等。掌握滑动窗口的关键是明确“窗口收缩的时机”什么时候右指针右移什么时候左指针右移什么时候更新结果。建议把这类题集中刷几天形成统一的思考框架比每天零散刷一两道有效得多。3.4 动态规划怎么打底别怕这名字很多备考者一听动态规划就头皮发麻其实机试中的动态规划并没有那么可怕因为高频考点就集中在几个基础模型上。最值得优先掌握的是最基础的线性DP比如最大子数组和、打家劫舍、最长递增子序列、背包问题变形0-1背包、完全背包、编辑距离类问题、路径问题机器人走格子、最小路径和。这些模型的共同特点是状态转移方程模式化你只要把原始模型吃透考试中遇到变形题也大概率能套上。我的打底方法是三步。第一步背模板。没错是背动态规划的经典题必须先把标准解法背熟尤其是状态定义和转移方程。第二步画表格。自己在纸上把DP数组的求解过程画一遍比如编辑距离问题画一个m乘以n的表格把每一个格子的值根据转移方程填出来填完你就彻底理解“状态从哪里来”了。第三步改条件。把背包容量改大把物品价值改成负数把求最大值改成求方案数用变形题来检验自己是否真懂。还有一个提高通过率的小技巧虽然动态规划是考察重点但机试中很多DP题其实存在替代解法。比如LIS可以二分贪心背包问题可以用DFS剪枝在数据较小的情况下通过编辑距离类题如果长度允许甚至可以写记忆化搜索。备考时别把所有宝押在“必须写出状态转移”上多留几条后路考场上的心理压力会小很多。3.5 模拟题工程能力的试金石最后一类高频考点是模拟题有时候也叫“大模拟”或“看说明写代码”。这类题算法本身可能不难但题面又长又绕对逻辑分解和代码组织能力考验更大。举个典型场景题目要求输入一段命令字符串需要解析命令参数、处理多项规则、输出格式化结果类似这种“小项目”式的题目在个别机试中很常见。这类题想拿满分最重要的是“先搭框架再填细节”。我习惯先定义好数据结构和辅助函数把主流程的骨架写出来再一个个补规则。千万别一边读题一边从头到尾线性写代码很容易写着写着就把前面某个规则忘了。模拟题的另一个关键点是测试用例意识。写完之后除了题目自带的样例一定要自己构造几组边界数据测一下比如空输入、极端长度、重复前缀等。很多时候机试的一次AC率低不是因为思路错而是因为代码没有覆盖“题面里没说但你该想到”的边界情况。4. 一次完整的机试复盘示例从读题到AC的全过程4.1 题目原型与题干为了让上面讲的方法更落地这里我拿一道典型的机试真题变体做一次完整复盘。这道题的原始风格很接近华为od机试真题和部分保研机试的中间难度经过脱敏改写后分享如下。题目给定一个整数数组和一个目标值要求找到数组中两个数的下标使这两个数之和等于目标值。输入有多组测试数据每组第一行包含数组元素个数n和目标值target第二行是n个整数。对每组数据输出两个下标要求较小的下标在前如果存在多个答案输出下标之积最小的一组。如果找不到输出“not found”。所有下标从0开始。看起来这就是“两数之和”的变体但多了三个考点多组读入、输出条件下标之积最小、找不到时的固定输出字符串。这三个考点单独拎出来都不难组合在一起就是一道非常典型的机试中等题。4.2 逐步拆解思路从暴力到最优拿到这道题第一步不是写代码而是想清楚解法。最笨的方法是两重循环对每组数据时间复杂度O(n²)如果n最大到10⁴、测试数据有10组那最坏情况就是10的9次方级操作在机试环境里大概率超时。用哈希表可以把复杂度降到O(n)。遍历数组时对每个元素检查target减去当前值是否已经出现过如果出现过就找到了答案。这里有个小细节题目要求输出下标之积最小的一组如果存在多个答案通常哈希表方法在遍历过程中遇到的第一对找到的答案就是满足条件的因为下标小的元素会先进入哈希表而利用“当前元素大于等于之前元素”的遍历顺序可以保证找到的配对下标之积不是最大的。不过为了严谨我还是会在代码里对比一下当前找到的答案和下标的乘积。4.3 代码实现与复杂度说明这里给出一个Java语言的核心代码段保留了ACM模式的完整结构方便你直观感受考场上的代码风格。import java.util.*; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); while (sc.hasNextInt()) { int n sc.nextInt(); int target sc.nextInt(); int[] nums new int[n]; for (int i 0; i n; i) { nums[i] sc.nextInt(); } MapInteger, Integer map new HashMap(); int ansA -1, ansB -1; for (int i 0; i n; i) { int need target - nums[i]; if (map.containsKey(need)) { int a map.get(need); int b i; if (ansA -1 || a * b ansA * ansB) { ansA a; ansB b; } } // 注意相同元素值时保留小下标避免覆盖掉更优答案 if (!map.containsKey(nums[i])) { map.put(nums[i], i); } } if (ansA 0) { System.out.println(ansA ansB); } else { System.out.println(not found); } } } }这段代码里有两个机试中非常值得关注的细节。第一在写入哈希表时我判断了!map.containsKey(nums[i])看起来多余但实际上防止了重复元素覆盖下标导致“下标之积最小”条件失效。比如数组是[3, 3]target是6如果不加这个判断第二次遇到3时会把下标1覆盖为0之后遍历不到新元素答案变成“0 1”这没错但如果换成[2, 2, 3, 3]target是5可能会出现下标组合选择不当的情况。第二在找到更优答案时才更新用一个初始为-1的哨兵标记判断是否已找到过答案。这个实现的时间复杂度为O(n)空间复杂度为O(n)。对于机试场景这类优化是必要的因为测试数据卡时间很常见。4.4 从这道题里延伸出的备考经验我拿这道题做复盘不只是因为它经典更是因为它的变形空间特别大。你可以试着把“求和”改成“求差”把“找下标”改成“判断是否存在”把“哈希表”换成“先排序再双指针”每一种变形都对应一类新题。备考时养成这种“一题多变”的习惯比无脑刷新题收益高得多。另外这道题的多组读入结构和输出格式也提醒我们每次写完代码一定要核对输出是否和题面要求完全一致包括空格、换行、大小写。很多机试平台对输出是逐字符判定的多打一个空格都会判错这属于最可惜的扣分项。5. 常见问题与避坑指南机试现场的血泪教训5.1 环境与工具的使用细节机试环境五花八门有的平台提供本地IDE有的只能在网页编辑器里写还有的干脆只能用命令行编辑器。我建议在备考阶段就尽量模拟目标机试的环境尤其是那些只能网页答题的平台平时刷题就别老依赖本地IDE的自动补全和编译错误提示。网页编辑器常见的坑包括编译器版本偏老、不支持某些C17特性Java不支持lambda表达式部分老平台会有这个限制Python版本是2还是3需要提前确认。如果不确定目标平台支持什么特性在考场上最保险的做法是用最基本的语法写代码少用花哨的语法糖。调试方面很多机试平台不提供断点调试唯一的调试手段就是打印中间变量。我自己的习惯是写代码时先预留几个“调试打印”的位置比如循环体的入口处、递归的返回处、关键变量的赋值处等样例通过后再统一注释掉。千万不要一边调试一边在原代码上乱加输出最后忘了删直接导致输出格式错误。5.2 代码层面的经典翻车现场这里整理一个机试高频翻车清单都是我见过或亲身踩过的坑数组越界最常见的是从1开始遍历数组却忘了给数组多分配一位空间。C语言和C里这种错误不会马上报错而是“运气差时崩溃运气好时跑出诡异结果”。整数溢出Java的int是32位两个大数相加可能溢出变成负数。如果题目给的数据范围到了10⁹级别直接用long别心存侥幸。递归爆栈DFS深度达到十万级时Java和C的默认递归栈会溢出解决方法要么改成显式栈要么用BFS替代。字符串比较C语言里比较字符串内容要用strcmp用等号比较的是指针地址这个新手常犯但有些备考者也偶尔迷糊。浮点数比较题目要求输出精度时别用double之间的等号判断相等要用差值绝对值小于某个epsilon。机试中涉及浮点数的题不多但一旦涉及精度问题非常棘手。5.3 时间分配与心态管理机试的时间分配通常有两种策略。第一种是“按分值分配”先快速把所有题都看一遍按预估难度给每道题分配时间优先拿稳分。第二种是“按顺序推进”从第一题开始逐个击破。我经历过多次实战后更推荐第一种尤其是题量较大的机试。具体操作建议考试开始后的前10分钟把所有题目都读一遍在草稿纸上写下每道题的大致思路和预估耗时。然后选择最有把握的两道题先写掉把保底分数拿到手。接下来再集中火力攻克剩余题目。如果某道题卡了30分钟还没有任何突破性思路果断跳过最后如果还有时间再回头补。心态方面一个很实际的经验是不要追求所有题全AC那是竞赛选手的目标。机试通常看总分或排名你只要保证能做对的题全部AC就已经能超过大部分人了。很多人在考场上因为死磕一道难题导致后面几道简单题没时间写这才是最典型的战略失误。5.4 考前24小时清单按这个准备不会慌根据我的经验整理了一份考前24小时的可执行清单基本覆盖了最常见的遗漏点。确认考试时间和平台入口提前在本地试登录别等到开考前10分钟才找链接。确认机试平台的编译器版本和编程语言支持范围准备好自己最熟悉语言的输入输出模板。准备一张草稿纸和笔部分线上机试允许使用提前问清楚规则。准备好自己的代码模板包括快读模板、常用数据结构的初始写法、二分查找边界模板。当然这些模板能不能带进考场要看平台规则有些平台不允许本地查资料那就提前把模板背到条件反射的程度。睡前一小时别刷难题看自己的错题归档或者干脆休息。机试是脑力活睡眠充足比临场突击重要得多。写在最后的体会写到这里我回头看了一下全文最想强调的还是开头那句话机试是一场工程能力的体检不是算法竞赛的选拔。备考时抓高频、抓基础、抓边界、抓输入输出、抓错题复盘远比追求刷题数量和难题深度更有价值。我自己每次准备机试前都会把核心数据结构和基础算法模板过一遍再把错题归档翻一遍这个习惯延续了好几年也推荐你试一下。希望这份刷题攻略能帮你少走弯路在下一场机试里稳稳发挥出真实水平。