ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

小米算法岗第一批笔试备考攻略:题型拆解与高频算法实战

小米算法岗第一批笔试备考攻略:题型拆解与高频算法实战 今年秋招算法岗的情况大家多少都有体感前几年那种“海投简历就有面试”的好日子基本过去了笔试环节成了第一道硬门槛。我身边不少朋友在准备小米集团算法岗的时候第一个碰到的就是“第一批笔试”。这名字听起来平平无奇但里面信息量其实不小它意味着卷子不是往年固定题库而是按批次滚动出题题目质量和难度也会随批次浮动。这篇文章不打算灌鸡汤也不搞什么“X天速通大厂笔试”的玄学。我想从一个实际参加过、也陪跑过几轮校招的视角把小米算法岗第一批笔试这件事拆开聊题型结构大概长什么样编程题怎么审题、怎么写能多拿分哪些算法是高频考点以及那些笔试时容易踩的坑。不管你是刚刷完力扣准备试水还是已经被几场笔试虐过想针对性补强这篇文章应该都能给你一些能直接用的东西。1. 先聊聊小米算法岗笔试到底考什么1.1 “第一批笔试”是什么批次差异有多大小米的秋招一般会分好几个批次滚动安排第一批笔试通常挂在简历投递截止后的两周内。很多同学会纠结“第一批是不是更难”或者“第一批是不是更简单”我的看法是这个问题没有标准答案但第一批有一个特殊的地方——它往往是题库更新后的第一批卷子题目风格会直接影响后面几个批次的走向。从实际操作看小米的笔试系统和很多大厂一样用的是牛客或者赛码这类在线笔试平台题目从题库中随机抽。这意味着同一批次的同学拿到的题可能不完全一样但题型结构和难度区间是大致对齐的。所以“第一批笔试”更像是一个时间节点概念而不是难度分层概念。与其纠结批次不如把精力放在摸清出题风格上。1.2 算法岗位不只是考算法有个误区得先说清楚算法岗笔试不一定只考纯算法。小米的算法岗方向很宽有做 NLP 的、有做 CV 的、有做搜广推的也有做机器学习平台的。不同方向的面试官关注点不同但笔试环节通常是统一出题考察的还是“通用算法能力 数据结构基础 机器学习基础”这个三角。我印象里这类笔试的选择题部分经常会出现统计概率、机器学习基础概念比如过拟合的处理方式、正则化的作用、常见损失函数的适用场景等。编程题则以数据结构和经典算法为主很少出现需要依赖某个特定框架或深度模型的题目。这个布局其实挺合理笔试环节考察的是“你作为算法工程师的基本盘稳不稳”而不是“你会不会调某个库”。1.3 难度定位比周赛简单比 Easy 略难如果非要给个参考系我个人体感是小米算法岗笔试的编程题难度介于 LeetCode 的 Easy 和 Medium 之间个别题会摸到 Medium 中上水平但很少出现 LeetCode Hard 级别的压轴题。牛客周赛的 T1、T2 难度差不多能覆盖大半。不过别高兴太早“难度不高”和“分数高”是两码事。笔试评分往往按通过率精确到小数有些题看似简单但边界条件一多很容易掉进细节陷阱。比如数组越界、空输入、整数溢出这些都是实打实的失分点。后面我会专门展开讲。2. 题型结构与考点分布拆解2.1 选择题数据结构与机器学习基础五五开选择题通常是 15-20 道每道题分值不大但架不住量大。从过来人的经验看高频考点集中在几块数据结构KMP 算法的 next 数组计算、排序算法的稳定性和时间复杂度、堆的建堆过程与复杂度、二叉树的遍历序列还原、哈希冲突的解决方法。算法设计贪心算法的适用场景、动态规划的 state 设计、二分查找的边界写法、Dijkstra 与 Floyd 的适用条件。机器学习过拟合与正则化、偏差方差分解、常见评价指标准确率、召回率、F1、AUC、梯度下降变体的区别、交叉验证的作用。这里特别提醒一句KMP 的 next 数组是选择题的常客而且经常不是让你写代码而是给你一个具体的模式串让你直接写出 next 数组或失配后的跳转位置。这种题很多人平时写代码是“背模板”一落到手算就懵后面我会拿具体例子演示一遍。2.2 编程题场景包装下的经典模型编程题一般是 2-3 道每道题 20-30 分。小米的出题风格有个特点喜欢给题目套一个业务场景的外壳但剥开之后核心还是经典模型。举个例子某道题表面是说“工厂流水线上 N 个任务每个任务有开始时间和结束时间安排最优调度”本质上就是区间调度问题贪心一排序就能做。还有的题说“给一串订单按价格和下单时间排序”其实就是多关键字排序。这种包装本身不可怕可怕的是你在考场上被场景带跑了没抽出背后的数学模型。我的建议是读题时拿笔把题目里的数字、范围、约束条件圈出来然后马上问自己三个问题——这个需求对应什么数据结构什么算法模型有没有经典的板子能直接套2.3 高频考点的优先级排序为了让大家准备的时候有个轻重缓急我根据自己的经验列了个优先级表格按“出现频率 × 投入产出比”排的优先级知识点常见考查方式必考数据结构数组、链表、栈、队列、哈希选择题 编程题底层支撑必考排序算法复杂度与稳定性选择题高频高频二分答案 / 二分查找编程题高频高频贪心算法编程题高频结合排序高频动态规划一维 / 二维背包 / 序列DP编程题中高频中频图论BFS / DFS / 最短路径编程题中频中频字符串KMP 手算、前缀哈希选择题中频编程题低频中频树遍历、最近公共祖先选择题 编程题低频低频数论快速幂、素数筛选择题低频编程题偶见低顺位复杂算法线段树、后缀数组、网络流基本不考少见但非绝对提示这个优先级不是绝对的比如个别批次可能突然冒出一道偏门的数论题。但从“投入产出比”角度讲线代排序动态规划这几个方向是性价比最高的先把必考和高频吃透比盲目刷难题划算得多。3. 编程题的核心套路与临场解题流程3.1 拿到题先别急着敲代码很多同学一上考场就紧张看到题目开头有一大段场景描述直接跳过去找输入输出格式然后稀里糊涂开始写。这个习惯非常危险。笔试的编程题藏分点往往就在场景描述里比如“任务可以并发执行”和“任务串行执行”就是两种完全不同的解法前者可能是贪心 堆后者可能只是简单累加。我的习惯是读题读两遍第一遍通读搞明白题目在说什么第二遍精读把输入范围、边界条件、输出要求圈出来。尤其是数据范围它直接决定你敢不敢用 O(n^2) 的解法。如果 n ≤ 10^5O(n^2) 大概率超时得想 O(n log n) 或 O(n) 的解法如果 n ≤ 500那 O(n^3) 都可能能跑过暴力枚举先拿分再说。3.2 第一目标先拿暴力分再谈优化笔试和面试不一样面试你可以跟面试官讨论思路笔试只看最终代码的通过率。所以一个非常实用且我反复验证过的策略是如果一时半会想不出最优解先写暴力保证拿到部分分数。举个例子一道题要求计算“数组中所有连续子数组的和”最优解是前缀和 O(n)但如果你第一时间没想到可以先写两层循环枚举所有起点和终点。等这道题暴力版本写完了你大概率在写的过程中会发现重复计算的部分这时候再优化成前缀和就顺理成章了。暴力代码不是白写它是你的保底分也是你思考的跳板。3.3 将题目映射到算法模型的信号词做题时间久了会发现每类算法都有一些典型的“信号词”。我把它们列出来遇到这些词可以直接触发对应的算法板子“最大/最小化某个值” 数据范围较大优先考虑二分答案。“最多能完成多少/最少需要几次”可能是贪心或动态规划需要结合数据范围判断。“是否存在……路径/能不能到达”BFS 或 DFS图论题。“有多少种组合/方案数”动态规划概率很大。“按某个条件排序后处理”排序 双指针或排序 贪心。“相邻两个……之间的关系”栈、队列或 DP。“x 的 y 次方 / 取模的大数幂”快速幂。这套映射不是万能公式但能在几分钟内帮你圈定思考范围避免在错误方向上耗太久。3.4 写代码时的几个细节习惯考场上很多问题不是“思路不会”而是“代码细节没处理好”。我总结几个踩过坑的地方用 long long 别用 int。凡是涉及累加、乘法、下标计算不确定范围的尽量用 64 位整数笔试平台常见溢出错误大多源于 int 溢出。处理好空输入和极端数据。链表为空、数组长度为 1、全是负数的用例写代码前先在草稿纸上推一遍。输出格式严格对照题面。多了一个空格、少了一个换行都可能被判格式错误部分平台直接算 0 分。提交前至少自测 3 个用例题干给的样例、一个最小规模用例、一个极端用例都要跑。4. 高频算法专项拆解从原理到现场快速推导4.1 KMP 与 next 数组别再背模板了KMP 算法是选择题里的“钉子户”但它很多年都不直接考代码实现而是考 next 数组的手算。就拿一个典型的模式串 p abacaba 来说next 数组怎么推导先明确一种常见定义next[i] 表示模式串前 i 个字符组成的子串中最长相等前后缀的长度不包含子串自身。逐个位置看i0子串 a没有真前后缀next[0]0。i1子串 ab前缀 {a}后缀 {b}无交集next[1]0。i2子串 aba前缀 {a,ab}后缀 {a,ba}最长相等前后缀是 anext[2]1。i3子串 abac前缀有 a,ab,aba后缀有 c,ac,bac无相等next[3]0。i4子串 abaca前缀 a,ab,aba,abac后缀 a,ca,aca,baca最长相等前后缀是 anext[4]1。i5子串 abacab前缀到 abaca后缀有 b,ab,cab,acab,bacab最长相等前后缀是 abnext[5]2。i6子串 abacaba前缀到 abacab后缀有 a,ba,aba,caba,acaba,bacaba最长相等前后缀是 abanext[6]3。最终 next 数组是 [0, 0, 1, 0, 1, 2, 3]。理解这个推导过程比死记代码模板重要得多。考场上一旦给了别的模式串理解了原理就能随手推出来而背模板只能祈祷它考的原题。4.2 快速幂一道题拿下位运算和取模热词里频繁出现“快速幂算法”这个考点在笔试里确实偶有出现而且经常藏在“计算 a 的 b 次方对 p 取模的结果”这类题后面。先看朴素的循环乘法O(b) 的时间复杂度如果 b 是 10^9 级别必然超时。快速幂的核心思想是把指数 b 拆成二进制比如 a^13 可以拆成 a^8 × a^4 × a^1因为 13 1101₂。每次迭代把底数平方同时右移指数遇到当前二进制位为 1 就把累积结果乘上当前的底数。这就是 O(log b)。C 的参考实现long long fast_pow(long long a, long long b, long long mod) { long long res 1 % mod; a % mod; while (b 0) { if (b 1) { res res * a % mod; } a a * a % mod; b 1; } return res; }有几个细节要注意res初始化为1 % mod是为了处理 mod1 的极端情况a先取模是为了防止初始值过大溢出每次乘法后都取模保证中间结果始终可控。这些细节就是笔试里“都是思路为啥分数不一样”的差距所在。4.3 排序与堆会写 API 也得知道底层排序算法的选择题考点主要是复杂度和稳定性。有些同学用惯了std::sort问起来却说不出快排的最坏时间复杂度这不行。准备一个速记表排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性冒泡排序O(n^2)O(n^2)O(1)稳定选择排序O(n^2)O(n^2)O(1)不稳定插入排序O(n^2)O(n^2)O(1)稳定快速排序O(n log n)O(n^2)O(log n)不稳定归并排序O(n log n)O(n log n)O(n)稳定堆排序O(n log n)O(n log n)O(1)不稳定计数排序O(nk)O(nk)O(k)稳定顺带说一下建堆的时间复杂度这个高频坑。很多人以为建堆是 O(n log n)但实际上是 O(n)。原因是从最后一个非叶子节点往上做向下调整大部分节点只需要常数次比较整体代价摊还后是线性。选择题里如果问“构建一个 n 个元素的最小堆时间复杂度”答案是 O(n)不是 O(n log n)。TopK 问题也是编程题的老面孔。找前 K 大的数经典方案是用大小为 K 的小顶堆堆顶就是当前第 K 大的门槛遍历一遍数组遇到比堆顶大的就替换并调整堆时间复杂度 O(n log K)。如果 K 远小于 n这个方案比全局排序快得多也是面试官喜欢的思路。4.4 区间贪心一个模型吃透一类题热词里有一类“雷达覆盖”相关的题这类题剥开壳子就是区间问题的最经典模型给定若干区间选择最少个数的点使得每个区间都至少包含一个选中的点。贪心策略很简单按区间右端点从小到大排序然后维护一个last变量表示当前选中的最右端点。遍历区间如果当前区间的左端点大于last说明这个区间没被覆盖需要新增一个点并更新last为当前区间的右端点否则就继续复用之前的点。C 的核心写法struct Interval { double left, right; }; vectorInterval intervals; // 按右端点排序 sort(intervals.begin(), intervals.end(), [](const Interval a, const Interval b) { return a.right b.right; }); int count 0; double last -INFINITY; for (const auto seg : intervals) { if (seg.left last) { count; last seg.right; } }这个模型的变体很多会议室安排、任务调度、灌溉范围覆盖等。关键点在于贪心选择的合理性证明——每次选在当前最右侧位置放置点能给后续区间留下最大空间这就是局部最优能导出全局最优的原因。考场上不要求严格证明但心里要清楚为什么这么排序。4.5 二分查找两个板子解决边界恐惧二分查找的代码实现细节是笔试选择题和编程题的双重高发区。闭区间和左闭右开区间是两套主流写法混着用容易越界或死循环。我建议只练一种左闭右闭。// 在 [l, r] 区间内查找第一个 target 的位置lower_bound int lowerBound(vectorint nums, int target) { int l 0, r nums.size() - 1; while (l r) { int mid l (r - l) / 2; if (nums[mid] target) { r mid - 1; } else { l mid 1; } } return l; } // 查找第一个 target 的位置upper_bound int upperBound(vectorint nums, int target) { int l 0, r nums.size() - 1; while (l r) { int mid l (r - l) / 2; if (nums[mid] target) { r mid - 1; } else { l mid 1; } } return l; }记住这套模板的核心当nums[mid] target时压缩右边界当nums[mid] target时压缩左边界。最终l指向的就是答案位置。这样不管题目问的是“找到 target 的第一个位置”还是“插入位置”都能直接套。mid 用l (r - l) / 2而不是(l r) / 2是为了防止 l r 整型溢出。4.6 动态规划拿到题先做这三步动态规划在算法岗笔试里的出场率很高一维 DP、二维 DP、背包类 DP 都常出现。我拿到一个疑似 DP 的题喜欢按三步走第一步定义状态。一维 DP 时想清楚 dp[i] 代表“以第 i 个元素结尾的最优值”还是“前 i 个元素的最优值”这两者有本质区别。第二步找转移方程。把第 i 个状态跟前几个状态联系起来这一步考验的是对子结构关系的理解。第三步初始化与遍历顺序。dp[0] 或 dp[1] 给多少外层循环从哪开始内层循环方向是正还是倒这些细节直接决定代码能不能跑对。比如经典的最长回文子串问题dp[i][j] 表示第 i 到第 j 个字符是否是回文转移方程是dp[i][j] (s[i] s[j]) (j - i 2 || dp[i 1][j - 1])。这种情况下遍历顺序就不能单纯从 0 到 n而要按子串长度从短到长否则用到的 dp[i1][j-1] 还没算出来。这种细节就是笔试里真正拉开差距的地方。5. 常见问题与排查技巧实录5.1 时间分配选择题别恋战80-100 分钟的笔试选择题加编程题各占一半时间通常是合理的。但很多同学会在选择题上死抠一道 KMP 手算题算了一遍觉得不对又算一遍十分钟没了。我的建议是选择题平均每道控制在 1 分半到 2 分钟超过 3 分钟还没思路就先标记跳过。编程题留足至少 50 分钟因为写代码、调试、自测都需要时间。如果最后编程题卡住了再回头补跳过的选择题也不迟。记住一个原则选择题分值再高也是单个选项编程题一跑通就是大几十分投入产出比完全不在一个量级。5.2 边界条件失守最容易丢分也最好拿回边界条件失守是编程题最常见的丢分原因但它恰恰是准备成本最低的提分点。每次写完代码花 30 秒自查一遍输入为空时你的代码会返回什么会不会越界n1 时循环和递归能正常处理吗数组下标有没有可能出现 -1 或 n累加结果会不会超过 int 范围题目要求输出浮点数时精度格式对不对这五个问题你要是每次提交前都过一遍编程题至少能挽回 5%-10% 的通过率。不要觉得这是小事校招笔试的分数分布非常密集几分之差就可能影响后续流程排序。5.3 笔试做题顺序先易后难是铁律考场上建议按照“一眼会的编程题 → 选择填空 → 不卡壳的编程题 → 难啃的编程题”的顺序进行。先做会做的题既能快速稳住心态也能确保基础分落袋。碰到一道题看了 10 分钟还没有完整思路先干别的事让潜意识再跑一会往往等回头再看的时侯就茅塞顿开了。另外编程题如果实在没思路裸写暴力也有意义。有些平台会按通过的测试点比例给分暴力能过一部分用例就是一部分别轻易放弃。5.4 批次与后续面试的衔接还有一个容易被忽略的点小米这种批次化笔试出分之后通常紧接着就是面试筛选笔试题目的复盘材料可能直接被面试官拿来追问。比如笔试考了动态规划面试官可能问“那道题你的状态定义是什么为什么这么定义还能怎么优化”所以笔试结束后不要立刻忘掉题目最好趁还有记忆把每道题的思路和代码整理下来这既是复盘也是为面试准备素材。我自己的习惯是笔试后 24 小时内写一篇简短的复盘记录题目类型、我的解法、优化方案、卡住的原因。这个习惯看起来麻烦但到了面试阶段非常有用——能说出清晰的思考过程和优化路径的候选人跟只写过代码的候选人完全是两个印象。6. 最后一点值得分享的个人体会笔试准备说到底不是看谁刷的题多而是看谁能把核心算法模型吃透、把细节控到位。小米这类大厂的算法岗笔试考察思路比较正统常规考点占比高偏题怪题很少。这意味着只要把数据结构、排序、二分、贪心、动态规划、基础图论这几块练扎实笔试通过并不是遥不可及的事。如果让我给准备 2025 届及以后批次的同学一个建议我会说把重点放在“理解算法原理 熟练模板 高频自测边界”上而不是去追求那些花哨的冷门算法。KMP 能手推 next 数组吗快速幂能默写吗二分的两个板子能闭眼写完吗这些问题如果都能快速给出肯定的答案那你面对的笔试题目大概率就已经拿下一大半了。最后再分享一个小技巧练习的时候多用纸笔手算算法过程别太依赖 IDE 的调试器。笔试环境里调试功能通常很弱而且选择题里的手算题根本不允许你调代码。每次刷题时先在大脑里把输入、状态变化、输出完整过一遍再动手敲键盘这个过程练得越多考场上就越稳。祝接下来笔试的各位都能顺利过关拿到自己心仪的 offer。有问题也欢迎在评论区交流我尽量抽空回复。
返回列表