ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

2025小米秋招软件开发笔试复盘:算法与底层考点全解析

2025小米秋招软件开发笔试复盘:算法与底层考点全解析 秋招季最磨人的不是简历石沉大海而是好不容易收到笔试通知打开试卷却发现题目风格和预期完全对不上。今年小米秋招笔试软件开发卷2出来之后不少同学在群里吐槽难度波动大、题型分布诡异。作为刚经历过这场笔试的人趁着记忆还热乎我把整张卷子的题目类型、考点分布、答题思路完整复盘一遍。这份复盘不是简单贴答案而是还原我在考场上的完整思考链路哪些题该果断放弃、哪些题必须稳拿、算法题怎么从暴力解一点点优化到最优解、基础题里藏着哪些小米特有的“硬件基因”考点。无论你是准备投递小米还是想摸底大厂笔试难度这份复盘都能给你一个比较准确的参照系。1. 拆卷之后的第一眼印象题量、分值与答题顺序决策1.1 整张卷子的结构小米的秋招笔试用的是第三方在线测评平台进入页面后自动全屏切屏次数过多会触发警告。卷2的题型分布大概是这样的第一部分单选题约20道第二部分多选题约5道第三部分编程题2道总分100分选择题共占40分左右编程题两道各占30分合计60分。这个分值配比值得玩味——小米显然更看重代码实操能力而不是死记硬背的基础知识。时间限制是90分钟但实际体感比这紧张得多。单选和多选一共25道看起来数量不多但有几道题涉及复杂计算和代码追踪每道可能要耗5分钟以上。编程题两道的难度都不低至少需要预留50分钟才能稳妥完成。所以我拿到试卷后的第一个决策是选择题按“1分钟1题”的节奏快速过遇到卡壳超过3分钟的先标记跳过去绝对不会在选择题上恋战。1.2 选择题的高频考点统计根据回忆选择题的考点主要集中在这几个方向考点模块出现频次典型题型数据结构基础5题栈、队列、二叉树遍历、哈希冲突C语言特性4题虚函数、智能指针、拷贝构造操作系统4题进程线程、死锁、内存管理计算机网络3题TCP握手、IP地址、HTTP状态码数据库2题索引原理、事务隔离级别Linux基础2题文件权限、常用命令数学逻辑3题概率计算、贪心策略这个分布其实很典型无论哪家大厂数据结构和语言基础永远是选择题的重头戏。操作系统和计算机网络作为计算机基础的核心占比稳定在20%左右。数学逻辑题的出现说明小米对候选人的逻辑推理能力有要求。1.3 时间分配上的真实操作我在做选择题时采用了“三轮法”第一轮把能秒答的题快速做掉多数是数据结构和语言基础类第二轮回头啃计算量大的操作系统、计算机网络题第三轮才对个别拿不准的数学逻辑题进行“基于选项特征”的合理猜测。这个策略的效果是25道选择题耗时约35分钟还剩55分钟分配给两道编程题——这个缓冲空间在后面的实战中起到了决定性作用。2. 算法题的三道坎暴力解法到最优解的现场取舍2.1 第一道编程题数组变换的最小操作次数这道题题目描述大概是给定一个整数数组每次操作可以选择一个元素将其除以2向下取整。问最少经过多少次操作能使数组中所有元素的和不超过某个给定阈值。乍一看这题很像“贪心最大堆”的经典套路。我当时的分析过程是每次操作对数组和的影响是把某个数x变成x/2向下取整数组总和减少的量为x - x/2 ceil(x/2)。要让总操作次数最少等价于每次选择减少量最大的那个元素进行操作。import heapq def min_operations(nums, target): total sum(nums) if total target: return 0 # 最大堆存入负数 heap [-num for num in nums] heapq.heapify(heap) cnt 0 while total target: x -heapq.heappop(heap) total - x - x // 2 heapq.heappush(heap, -(x // 2)) cnt 1 return cnt复杂度是O(n k log n)其中k为操作次数。这道题本身难度中等偏易关键在于能不能快速识别出“每次取最大”的贪心策略并熟练用堆实现。实测下来核心陷阱在于当x为奇数时x // 2 和 x // 2 的更新到底用整除还是浮点数这里必须时刻保持整型运算避免浮点数精度问题。对于这一题的稳健解法其实还有一个优化点如果数组长度很大、目标阈值很低、元素数值很大操作次数可能非常多此时可以用桶排序的思想按数值区间批量处理减少堆操作的log开销。不过笔试环境下标准堆解法已经足够AC。2.2 第二道编程题二叉树的层序锯齿遍历这道题要求按“之字形”顺序遍历二叉树第一层从左到右第二层从右到左第三层再从左到右依此类推。这道题属于必须拿稳的经典题。看到题目的第一反应是BFS队列逐层遍历用一个布尔变量记录当前层是否需要反转需要反转时将当前层的节点值列表reverse后再加入结果集。这个解法的时间复杂度O(n)空间复杂度O(n)。from collections import deque def zigzagLevelOrder(root): if not root: return [] res [] q deque([root]) left_to_right True while q: level_size len(q) level_vals [] for _ in range(level_size): node q.popleft() level_vals.append(node.val) if node.left: q.append(node.left) if node.right: q.append(node.right) if not left_to_right: level_vals.reverse() res.append(level_vals) left_to_right not left_to_right return res这道题还有一个更“节省”的实现方式——在每层入队时按相反顺序入子节点但边界条件很容易出错实际笔试完全不建议冒险。直接遍历后反转或使用双端队列从两端插入是最稳妥的选择。提示笔试中算法题的判题标准通常包含边界用例如空树、单节点树、节点值为负数等。提交前务必对极端场景做个快速自查。2.3 算法题之外的隐含考察点两道编程题做完我回头看了一下代码发现小米的在线编程环境有两点和其他大厂不一样第一默认代码模板非常啰嗦包含了大量注释和边界检查代码提交时如果没删除无关输出很容易导致编译错误或格式错误。第二输入输出的样例格式容易误导人——题目给的是一个比较宽松的描述但实际测试用例可能非常严格比如树节点的输入是以层序遍历数组形式给出空节点用null标记解析时需要对连续null做特殊处理。另外值得一提的是小米的判题系统对时间限制的设置比较紧。第一道题如果用排序后逐个减的暴力方法碰到极端数据大概率超时。笔试环境不能像本地IDE一样随意调试合理利用注释和打印来调试是关键。所以平时练习刷题时最好养成先明确数据范围和复杂度约束再动手编码的习惯而不要拿到题就开始写循环。3. 基础题里的“小米特色”操作系统、网络与硬件结合点3.1 操作系统题的考察角度比想象中更“底层”选择题中操作系统部分出现了不少与硬件结合紧密的题。比如有一道题问在操作系统启动过程中CPU从复位到执行用户进程经历了哪些关键模式切换选项涉及实模式、保护模式、中断描述符表等。这题如果只是背过“进程调度算法”和“虚拟内存”是答不出来的必须对Intel x86架构下CPU的模式切换有基本了解。小米是做硬件起家的招聘软件开发工程师时对Android底层、驱动、BSP等相关方向有持续的需求所以笔试中考到这类底层的系统启动流程并不意外。另一道印象深刻的题目是关于Linux的进程调度下列说法正确的是 A. CFS调度器是基于时间片轮转的 B. 实时进程的优先级高于普通进程 C. nice值越小优先级越高 D. 时间片耗尽时进程进入僵尸状态这道题的关键是区分“正确”和“完全正确”。CFS完全公平调度器实际上是基于虚拟运行时间来进行调度不是简单的固定时间片轮转所以A是错的。B看起来对但“实时进程优先级高于普通进程”不够严谨应该说是“实时进程的调度策略优先级高于普通进程”在某些特殊配置下并不是绝对成立。C是对的nice值范围是-20到19越小优先级越高。D很有迷惑性时间片耗尽应该进入就绪状态等待调度而不是僵尸状态。正确答案是C。3.2 计算机网络题的细节陷阱网络部分有三道题其中一道是TCP三次握手的变体在TCP连接建立过程中客户端发送的第二次握手报文SYNACK同时属于 A. 客户端发送给服务端的确认报文 B. 服务端发送给客户端的SYN请求 C. 服务端发送给客户端的ACK确认 D. 以上全部正确答案是D。二次握手报文是服务端在收到客户端的SYN之后回复SYNACK它既是对客户端SYN的确认ACK同时自身也携带SYN标志来请求同步。很多同学容易把三次握手的报文归属搞混特别是在“这个报文是谁发给谁的”这种细节上。这里建议记住一个口诀第三次握手是纯ACK第一次握手是纯SYN第二次握手是SYNACK。另一道题考了HTTP状态码的语义当服务器理解请求但拒绝执行时应返回的状态码是 A. 400 Bad Request B. 401 Unauthorized C. 403 Forbidden D. 404 Not Found答案是C。400是语法错误401是未认证403是已认证但无权限404是资源不存在。这道题其实考验的是对HTTP协议语义边界的理解如果只看过一遍状态码表而没有深入理解“401和403的区别”很容易在这道题上翻车。3.3 数据库索引的“反直觉”题数据库题有两道其中一道关于索引的题目比较有意思在InnoDB存储引擎中关于聚集索引Clustered Index的说法正确的是 A. 每张表可以有多个聚集索引 B. 聚集索引的叶子节点存储的是整行数据 C. 二级索引的叶子节点存储的是指向数据的物理地址 D. 使用聚集索引查询一定比全表扫描快这道题的正确答案是B。InnoDB的聚集索引就是主键索引一张表只能有一个聚集索引叶子节点存放整行数据。C是易错项二级索引的叶子节点存储的是主键值而不是物理地址——如果要通过二级索引查找完整行数据还需要“回表”到聚集索引中再查一次。D是典型的绝对化表述陷阱“一定比全表扫描快”这句话在任何涉及数据库的面试题里出现都要高度警惕当查询条件的选择性很差或者表数据量很小时优化器完全可能选择全表扫描。3.4 Linux题和C题的基础盘Linux相关的两道题都是送分题级别文件权限chmod 644对应的权限是“属主读写属组读其他读”查看端口监听状态用netstat或ss命令。这类题目只要平时接触过服务器基本都能秒答。C题里有一道虚函数相关的问题值得记录含有纯虚函数的类称为抽象类以下说法正确的是 A. 抽象类可以实例化 B. 抽象类不能作为基类 C. 派生类必须实现所有纯虚函数才能被实例化 D. 抽象类可以定义对象数组正确答案是C。抽象类不能实例化但可以作为基类派生类只有实现了所有纯虚函数之后才不再是抽象类才能实例化。C多态的基础是虚函数表vtable只要类中有虚函数编译器就会为这个类生成一个虚函数表对象的内存布局中会多一个指向vtable的虚指针这是常见八股但也是理解多态的前提。4. 编程题的实战拉锯从调试崩溃到AC的完整过程4.1 第一道题在堆的边界条件上栽了跟头第一道数组变换题我写得很顺但提交之后发现只通过了60%的用例。当时第一反应是算法有问题但仔细分析后发现每次减少量为x - x//2如果数组中有0元素堆顶弹出0之后0//2还是0程序会陷入死循环total永远不会低于阈值。这是我第一次栽在边界条件上。修正方法是在弹出堆顶时判断如果x 1说明当前数组已经不能再继续减小了此时直接返回-1表示无法达到目标。if x 1: return -1这个边界条件在题目描述中并没有明确说明但测试用例显然包含了“不可能达成目标”的场景。这提醒我读题后先花10秒思考极端情况——数组全0、只有一个元素、目标为负数、元素大于2^31做这类检查比自己写完后再回头看要高效得多。4.2 第二道题在输入解析上耗费了时间二叉树的输入样例是以数组形式给出的比如[1,2,3,null,null,4,5]。一开始我试图用递归方式还原二叉树但Python的递归深度限制在这种场景下是个隐患。后来改成用队列迭代建树虽然代码量多了一些但逻辑更加直观也不会有递归栈溢出风险。这道题的另一个坑是“空节点到底怎么表示”——有时候题目写null有时候写#有时候写-1。虽然题目描述中有说明但在紧张的考试环境下很容易看漏。稳妥做法是写一个通用的解析函数不依赖具体的空值标记而是在循环中判断字符串是否为常见空值标记。4.3 本地测试和在线判题的差异笔试结束后我复盘时发现两道题里我各写了一版“能过本地样例”却“在线判题崩溃”的代码。主要原因一是本地Python版本和在线环境版本不一致。比如说我在本地用Python 3.10跑通的代码在线环境可能用的是3.8一些语法特性不兼容。笔试环境不让选择语言版本时最稳妥的做法是只用最基本的语法不要依赖新特性如字典合并操作符|、内置泛型list[int]等。二是死循环检测机制。在线判题系统通常有超时限制如果代码在某个边界用例下陷入死循环会直接判超时而不是给你一个清晰的错误信息。这时候只能靠人工审查代码逻辑来定位问题无法像本地IDE一样查看当前执行到哪一行。三是输出敏感性问题。在线判题系统对输出格式非常敏感多打印一个空格、少打印一个换行都可能导致Wrong Answer。建议在提交前把代码里的调试打印全部删除或注释掉并严格按照题目给的输出格式进行提交。5. 错题背后的知识盲区与针对性补强5.1 在智能指针题上暴露的现代C短板这个知识点在考后复盘时反复提醒我因为问题本身很有迷惑性以下关于std::shared_ptr的说法错误的是 A. 多个shared_ptr可以指向同一个对象 B. shared_ptr使用引用计数来管理对象的生命周期 C. 两个shared_ptr互相引用时会导致内存泄漏 D. shared_ptr可以安全地在多线程中对同一个对象进行拷贝和析构正确答案是D。shared_ptr的控制块包含引用计数但这个计数器的操作虽然说是原子的同一个shared_ptr对象被多个线程同时调用拷贝构造或析构并不保证线程安全——线程安全指的是多个shared_ptr实例指向同一个对象时它们各自管理自己的引用计数副本是安全的但同一个实例的并发修改仍然需要外部同步。这道题暴露了我对“引用计数线程安全性”的理解只停留在表层。现代C工程中智能指针是基础中的基础但这个知识点在平时的刷题和八股中很少被深入问到。笔试结束后我特意把《Effective Modern C》中智能指针相关章节重新啃了一遍把shared_ptr、unique_ptr、weak_ptr的使用场景、性能开销、线程安全性整理成了一张对照表。5.2 概率推理题的“数学味”比预期浓小米的数学逻辑题不像互联网大厂常规的行测逻辑而是更偏向计算机科学中常用的概率分析。有一道题印象很深某系统有4个独立模块每个模块正常运行的概率为0.9只要任意3个模块正常系统就能运行问系统正常运行的概率这个实际上是4选3的可靠性模型。正确解法是计算恰好4个正常的概率加上恰好3个正常的概率。P C(4,4) * 0.9^4 C(4,3) * 0.9^3 * 0.1 0.6561 0.2916 0.9477答案是0.9477约94.77%。这道题本身不难但要求能快速反应出“至少3个正常”等价于“4个全正常恰好3个正常”。如果平时没做过这类可靠性模型题现场容易陷入不必要的复杂计算中。5.3 一道变形版的哲学家就餐问题多选题里有一道关于死锁的题不是直接问“死锁的四个必要条件”而是给了一个场景5个哲学家围坐一桌每人左手拿一个叉子右手拿一个叉子但叉子只有5把。问这个场景中发生死锁的根本原因是什么。这道题考的就是死锁的“循环等待”条件。选项包括 A. 互斥条件 B. 持有并等待 C. 不可剥夺 D. 循环等待答案是全选。五个哲学家都先拿左手叉子再去拿右手叉子会形成循环等待。但如果改成“先拿编号小的一边”就能破坏循环等待避免死锁。这个考点本身不难难的是以场景题形式出现时很多同学容易漏选“互斥条件”或“不可剥夺条件”。做这类多选题的教训是不要只盯着明显的选项要把死锁的四个必要条件逐一和题干条件核对逐个验证后再做选择。6. 这份卷子给我带来的备考策略调整6.1 基础题的重心从“广度”转向“深度”小米卷2的基础题覆盖面不算特别广但每道题都在往深处挖掘。比如操作系统考到CPU启动流程、数据库考到二级索引的回表机制、C考到智能指针跨线程操作安全性。这些都不是那种“背一背就能答”的浅层内容而是需要真的理解底层运作机制才能答对。所以后续备考大厂笔试时我调整了自己的复习重心——不再追求“把所有八股题背熟”而是对每个高频考点下沉一层。比如面试的OS高频考点“虚拟内存”不只背“页表、缺页中断、LRU置换”而是追问自己64位系统下的四级页表怎么寻址TLB miss后硬件和操作系统各自做什么这种下沉式复习虽然慢但应付这类“深挖型”选择题反而更高效。6.2 编程题的训练模式改为“限时手写极端用例自查”这次笔试让我意识到LeetCode式的在线刷题在“输入解析”“边界处理”“超时保护”方面的训练是远远不够的。为此我给自己制定了新的训练方案每周至少3次限时手写代码练习用记事本而非IDE模拟笔试环境每道题完成后必须写出“极端用例清单”——空输入、单元素、大数值、负数、目标不可达代码中禁止使用语言新特性除非确认在线判题环境支持这样训练一段时间后我发现自己在笔试中犯的“低级错误”明显变少比如忘记处理空指针、数组越界、整型溢出等。提示如果投递的岗位偏向嵌入式或系统开发编程题的侧重点会明显不同。小米的嵌入式软件开发工程师笔试经常会出现位操作、寄存器配置、内存对齐相关的题目这类岗位的笔试准备方式要和纯软件开发区分开。6.3 做题节奏和心态管理的复盘90分钟做完25道选择题2道编程题节奏感非常重要。我个人比较舒服的节奏是时间段任务心态目标0-10分钟快速浏览全卷不慌张确认题型10-35分钟第一轮秒选题不恋战果断跳过35-40分钟第二轮啃难题每题最多5分钟40-55分钟第三轮猜测不空题选项特征辅助55-90分钟编程题先写对再优化这套节奏的核心逻辑是先确保编程题有充足时间而不是把时间耗在选择题上。毕竟一道编程题30分顶得上好几道选择题投入产出比完全不同。不过说实话真正考试时我的节奏并没有执行得这么完美。第一道编程题因为边界条件多花了10分钟导致第二道题的检查和优化时间被压缩。如果能重来一次我会在写完第一道题后先提交一版“暴力解能过部分用例”的代码然后再提交优化版这样即使后续优化失败也不至于整个题丢分。6.4 一些有价值的工具和资料整理备考过程中我逐渐筛选出了一套比较高效的资料组合。刷题方面LeetCode的热题100和剑指Offer覆盖了大部分笔试算法题的类型但建议按照数据结构类型进行专项练习而不是随机刷题。比如集中三天只做二叉树相关的题目再做动态规划这种成体系训练对笔试的短期提分效果更明显。基础知识的复习可以参考小林coding的图解系统、图解网络配合牛客上的历年大厂笔试题——但一定要警惕“背答案”的误区。笔试中同一道题往往会换一个场景、换一种问法只有理解背后的原理才不会被变化的外壳迷惑。写在最后的一点个人体会小米秋招软件开发卷2的整体风格是基础扎实、算法不偏、底层味浓。没有那种故意刁难人的偏题怪题但每道题都在考察“候选人是不是真的理解”而非“候选人是不是背过”。如果你正在准备大厂秋招笔试我个人的建议是算法题练习固不可少但一定不要忽视基础知识的深度理解。现在的大厂笔试越来越倾向于“反八股”——即题目看着眼熟但提问角度刁钻专治各种死记硬背。真正能拉开差距的往往不是谁刷题多而是谁能把知识点扎得更深、连得更广。笔试只是秋招的第一道关后面还有更残酷的面试。希望这份复盘能帮你少踩一些我踩过的坑在真正的考场上更从容一些。
返回列表