小米2019秋招软件开发笔试题A卷:核心考点与备考策略全解析

📅 发布时间:2026/8/29 16:44:06
小米2019秋招软件开发笔试题A卷:核心考点与备考策略全解析 以前陪朋友模拟过一套校招笔试印象最深的是卷子刚发下来时前排考生齐刷刷翻页的声音不到一半人动笔的沉默。小米2019秋招软件开发笔试题A就是这么一套让人既紧张又想挑战的卷子。作为那几年口口相传的“经典款”它不算难到变态但覆盖面特别广数据结构、C/C与Java语法、网络协议、操作系统、逻辑推理甚至还有一点和智能硬件业务有关的底层概念两个小时之内你必须在多个知识模块之间来回切频道。如果你正在准备软件开发岗的校招笔试这套题很适合拿来做一次自测它可以帮你快速摸清自己的知识短板在哪里。下面是我结合当年考友的回忆、题库风格和同类题型的整理把A卷值得重点复盘的内容完整梳理一遍。1. 试卷整体画像这套A卷到底在筛选什么能力1.1 题量与时长从常见笔试配置看时间压力小米2019秋招软件开发笔试题A的总体配置和当年大多数互联网公司类似大约是120分钟60到70道题目题型包括单选、多选、判断、填空外加两道编程题。这套试卷的姿态比较直白不跟你绕弯子但也不会故意放水。选择题里有一大半不是考某个单一语法点而是考你能不能把多个知识点连起来用。比如“这个C语言代码在32位系统上运行输出是什么”一道题里同时牵扯sizeof、内存对齐、数组名退化为指针三个点任何一个环节有漏洞答案就会偏。真正让人觉得手忙脚乱的往往不是题目数量而是时间。120分钟看起来不算短如果先做选择题再写两道编程题时间安排得好其实够用但很多同学在单选上花费过多一道题反复纠结五六分钟等做到编程题就只能草草写个框架。我的建议是拿到试卷后先快速浏览一遍编程题心里有个底再回头做选择题。这套题的时间压力是可控的前提是你对各考点的结论比较确定不在一道题上消耗大量犹豫成本。1.2 模块权重哪些知识点会反复出现根据考后大家拼出来的题目分布可以画出一张接近真实的模块权重表模块大致占比常见出题形式数据结构与算法35%-40%选择、填空、编程C/C/Java语言基础15%-20%选择、读代码写输出计算机网络10%-12%选择、判断、填空操作系统10%-12%选择、判断、填空逻辑推理与数学5%-8%选择、填空开放/工程题5%-10%简答、设计题从这个分布能看出来算法和数据结构是毫无疑问的主战场。这不是小米的特殊风格几乎所有互联网和智能硬件公司的软件开发笔试都这样安排。原因很简单笔试是笔试不是面试它没法直接考核工程经验和项目质量只能用算法题衡量一种相对公平的“思维基础”。所以准备这套题的正确顺序一定是先把算法和数据结构的基础打牢再去看语言细节和网络协议否则很容易出现“编程题做不出来简答题背了一堆却踩不上采分点”的情况。1.3 A卷与B卷的区分逻辑小米那几年秋招会同时出多套卷子A卷和B卷的区分并不一定是难度差异更多是岗位方向差异。A卷通常对应软件开发工程师这种通用型岗位语言上偏向C/C和Java知识点更偏通用计算机基础。B卷则会更针对嵌入式或客户端开发方向加入更多底层内容比如内存布局、寄存器操作、中断处理这些。所以如果你拿到的就是A卷不用太担心硬件底层内容会考得特别深它出现的概率整体不高但如果出现几道和嵌入式沾边的题也不要意外毕竟这和公司业务方向有关。下面的题目梳理我主要依据的是当年考友们对“同类型题目”的回忆和整理并不是原题默写但考点和解题思路完全可以拿来当备考参考。2. 算法与数据结构拿分主战场的四类必会题型2.1 数组类问题双指针和前缀和是最基础也最好用的武器数组题在A卷里的出现频率非常高而且形式变化多。常见的有求连续子数组的最大和、数组去重、两个有序数组的合并、查找目标值在排序数组中的位置等。这类问题最常用的套路就两个双指针和前缀和。先讲双指针。经典场景是“数组中两个数之和等于目标值”。如果题目明确说明数组有序那就一个指针从头走一个指针从尾走根据当前和与目标值的大小关系移动其中一边时间复杂度O(n)。如果返回的是下标且数组无序就得用哈希表辅助遍历时检查target - nums[i]是否已经出现过。笔试中这两种变体都可能出现答题前先判断数组是否有序直接决定了选哪条路。再说“连续子数组最大和”这道题有非常经典的一趟扫描解法笔试时最好能形成肌肉记忆class Solution { public int maxSubArray(int[] nums) { int cur 0; int best Integer.MIN_VALUE; for (int x : nums) { cur Math.max(x, cur x); best Math.max(best, cur); } return best; } }这段代码看着简单但里面有一个重要的思维转换不是去枚举每个子数组而是遍历到第i个元素时只考虑“以当前元素结尾的最大子数组”。每个位置上的局部最优一旦算出来全局最优就是这些局部最优里的最大值。这种“局部转移全局比较”的思路到了动态规划题你会再次遇到所以值得多花几分钟把它理解透。2.2 链表反转与链表中点边界条件决定生死链表在笔试选择里的高频考点包括反转链表、找倒数第K个节点、判断是否有环、合并两个有序链表。其中反转链表基本是必考题因为它虽然代码量不大却能考你对指针或引用操作的理解程度。迭代写法是最适合笔试的public ListNode reverseList(ListNode head) { ListNode prev null; ListNode curr head; while (curr ! null) { ListNode nextTemp curr.next; curr.next prev; prev curr; curr nextTemp; } return prev; }写这道题时最容易犯的错是先修改了curr.next再回头找原始的下一个节点结果把链表“走断”。所以迭代反转里第一步必须是保存nextTemp。考场上如果时间充裕建议先把链表图画出来标出prev、curr、next三个节点的位置关系再动笔能避免很多边界错误。找链表中点也有一个很实用的快慢指针套路快指针每次走两步慢指针每次走一步快指针到达末尾时慢指针正好在中点附近。当链表长度为偶数时“中点”的定义可能在两个节点之间不同题目有不同要求答题前务必确认要的是“前一个中点”还是“后一个中点”。这个细节比较隐蔽如果题目要求输出后半部分的起点你选错了位置整个结果都会跑偏。2.3 动态规划状态定义写对了题目就完成了一半动态规划是很多同学最头疼的板块但笔试里出现的DP题通常不会太难基本围绕“斐波那契类”“路径类”“打家劫舍类”和“背包类”展开。我的个人经验是拿到一道DP题不要急着写转移方程先做两件事第一明确状态的含义第二明确状态之间怎么转移。以“从矩阵左上角走到右下角每次只能向右或向下求路径上的数字之和最小值”为例状态可以定义成dp[i][j]表示到达(i,j)位置时的最小路径和。转移方程就是dp[i][j] min(dp[i-1][j], dp[i][j-1]) grid[i][j]同时注意第一行和第一列只能从一个方向过来要先单独初始化。这种题思路一旦理清代码非常短。还有一个容易踩的坑是“打印路径”问题。很多同学算出最小路径和就完事了但题目如果要求输出具体路径就不能只存数值必须在dp过程中把方向记录下来最后从终点倒推。这种附加要求往往是笔试编程题的“隐藏关卡”题目描述里出现“输出路径”四个字时一定要多留一块空间存方向数组。2.4 二叉树层序遍历是最容易临场卡壳的题二叉树的知识点里前中后序遍历、层序遍历、二叉树的最大深度、最近公共祖先都是高频考点。前中后序的递归写法最容易掌握但笔试为了区分度会要求非递归写法尤其是前序遍历和中序遍历的非递归实现用栈模拟递归过程。我见过不少同学能默写递归一遇到非递归就卡住建议备考时把三套非递归写熟练面试笔试都用得上。层序遍历则是另一个容易出问题的点。它的核心结构是队列先把根节点入队记录当前队列长度size这个size代表当前层的节点数循环处理size次每次从队首取出节点把它的左右子节点入队处理完后队列里正好是下一层的所有节点很多同学记不住“要先记录size”直接在循环里动态获取队列长度导致同一层的节点被切成两批输出结果就错了。笔试时如果遇到“按层输出”的题目可以先把队列长度缓存下来再做循环这个习惯能帮你省下大量调试时间。3. C/C与Java语言题隐藏在“基础题”里的丢分点3.1 数组和指针为什么这个考点反复出现“数组和指针笔试题”能成为高频搜索词说明很多人在这类题上栽过跟头。C语言的数组和指针总被放在一起考是因为它们在底层有联系但在语义上有明显区别。先记几个关键结论sizeof(arr)和sizeof(ptr)结果不一样。对一个10个int的数组来说在32位系统上sizeof(arr)是40在64位系统上是80sizeof(ptr)则是指针本身的大小32位是464位是8。数组的sizeof包含整个数组指针的sizeof只是指针大小。数组名作为函数参数传递时会退化为指针。函数形参写成int arr[]和int *arr在参数传递场景下没有本质区别。指针可以做加减运算ptr1表示跳过一个元素而不是跳过1字节。这个结论在选择题里经常被包装成“写出指针偏移后的地址值”。遇到这类题先把平台位数和变量类型写清楚再算尤其是地址计算题审题不仔细是最常见的失分原因。很多人明明知道指针加1跳过的是整个元素却因为没看清是char *还是int *把偏移量算错了。3.2 Java输出题类加载和继承初始化顺序的坑Java语言部分的考察重点包括类加载顺序、继承和多态、String不可变性、与equals的区别、集合类的线程安全性、异常体系等。其中“写出下列代码输出结果”这类题最容易挖坑的就是继承时的静态代码块、实例代码块和构造方法的执行顺序。顺序结论是父类静态代码块和静态成员初始化子类静态代码块和静态成员初始化父类实例代码块和普通成员初始化父类构造方法子类实例代码块和普通成员初始化子类构造方法这里有个容易混淆的地方静态代码块只在类第一次被加载时执行一次实例代码块每次创建对象时都会执行。笔试选择题里如果连续创建两个子类对象第一个对象和第二个对象的输出会不一样很多人没注意到静态部分只执行一次这个细节。3.3 那些“看起来简单但输出和你想的不一样”的场景给一个特别典型的例子很多考友复盘时都提到过类似的题String a hello; String b hello; String c new String(hello); System.out.println(a b); System.out.println(a c); System.out.println(a.equals(c));输出结果是true、false、true。a b为true是因为字符串字面量在常量池中会被复用a c为false是因为new一定会创建新的堆对象equals比较的是内容。这个知识点本身不难但考试会在此基础上扩展如果字符串用拼接结果是什么两个常量字符串拼接呢拼接结果包含变量呢对“引用”理解不够透彻的人遇到这些变体很容易出错。我的建议是Java字符串题不要死背结论要记住内存模型常量池、堆、栈各有分工。搞明白对象引用和对象本身的区别很多题看起来选项很绕实际上考的就是这一个底层问题。4. 计算机网络与操作系统简答和选择题的知识边界4.1 TCP为什么总被拿来出题三次握手相关问题在校招笔试里TCP协议几乎是必考内容因为它是理解网络通信的重要基础。常见考法有这么几种描述TCP三次握手的过程以及每一步各自的状态。注意不是只背“SYN、SYN-ACK、ACK”还要能说出服务端的SYN_RCVD、客户端的ESTABLISHED这些状态名。为什么需要三次握手而不是两次通常的解释是三次握手能防止已失效的连接请求报文段突然又传到服务端避免资源浪费。TCP和UDP的区别包括是否面向连接、是否可靠、是否提供拥塞控制、适合什么应用场景。HTTP层的知识也经常考。选择题喜欢问状态码的含义200代表OK301是永久重定向302是临时重定向404是找不到资源500是服务器内部错误。如果简答题问HTTP和HTTPS的区别除了提HTTPS使用了加密层最好还能说出证书、对称加密和非对称加密混合使用的过程。回答时不用写太多把关键链路写清楚就够了。4.2 进程与线程Linux下的实现差异操作系统部分进程和线程的考察频率比较高。比较常见的题型是“下面哪些说法是正确的”然后混合排列进程与线程的地址空间、调度开销、通信方式、崩溃影响等说法。常考结论可以整理成表维度进程线程地址空间独立共享同一进程地址空间资源开销创建和切换开销大创建和切换开销小通信方式管道、消息队列、共享内存、信号量等直接读写共享变量或用线程同步机制崩溃影响一个进程崩溃不影响其他进程一个线程崩溃可能导致整个进程退出适用场景强隔离、独立任务高并发、共享数据密集任务Linux相关的题还可能考到fork()这个系统调用调用一次返回两次在父进程中返回子进程PID在子进程中返回0。有些选择题会让你数程序执行后总共创建了多少个进程这种题只要记住“fork之后父子进程各自继续往下执行”就能推出来但注意别漏掉下一次循环里的fork计算时最好画一条进程树。4.3 内存管理与死锁高频选择判断考点操作系统内存管理常考分页、虚拟内存和页面置换算法。选择题比较偏爱“LRU和FIFO在给定访问序列下缺页次数分别是多少”这类计算题。做这种计算题务必画一个表一列一列往里填不要心算心算很容易漏掉“页面已经在内存中”的命中情况。死锁部分考的就是四个必要条件互斥、占有且等待、不可剥夺、循环等待。判断一个系统是否可能发生死锁、用什么办法破坏死锁条件这两类题几乎每次都会出现。回答时尽量做到“条件名对应破坏手段”一一对应比如资源一次性分配可以破坏“占有且等待”对资源实行抢占可以破坏“不可剥夺”。把四组对应关系记牢固选择题基本不会错。5. 逻辑题与工程题很多人最容易忽略的板块5.1 概率与计数题从情境理解开始逻辑推理与数学题在A卷里占比不高但出现的时候比较讨厌因为它考的往往不是你能背多少知识而是压力下能不能冷静地把题目翻译成数学语言。常见类型有病狗问题、天平找次品、抛硬币概率等。举一个典型的例子有9个外观完全相同的球其中一个稍重用天平最少称几次能找出来答案是2次。思路是把球分成三堆每堆3个先称其中两堆如果平衡重球就在第三堆如果倾斜重球就在沉下去的那堆里。确定在哪一堆后剩下3个继续用同样的策略。这类题的价值不在于答案本身而在“三分法”这个思想它本质上跟二分搜索、递归分治是同一个逻辑。笔试遇到陌生题时可以想想能不能用分治、状态压缩或者数学期望的方式去套。5.2 为什么小米这类硬件公司会考底层概念小米不仅是手机厂商旗下还有大量生态链硬件产品软件开发岗里很大一部分工作会和Android系统、嵌入式设备、底层驱动沾边。所以在A卷里偶尔会出现几道类似嵌入式软件开发面试题的选择题比如字节序大端/小端、结构体内存对齐、位运算、整数溢出判断。这些内容在课程里不一定讲得很深但对硬件相关的软件开发来说属于基本功。字节序有一个高频判断方法看0x12345678这个值的低地址字节。如果低地址存的是0x78说明是小端如果低地址存的是0x12说明是大端。选择题经常会给出一个联合体变量让你根据成员访问结果判断当前系统端序原理很简单但对union内存布局不熟的人容易卡住。结构体内存对齐考的通常是“这个结构体占多少字节”计算时记住对齐规则是成员按自身大小对齐整体大小是最大对齐数的整数倍。位运算也是容易被忽略的点。比如“不借助临时变量交换两个整数”可以用异或运算再比如用n (n-1)判断一个数是不是2的幂。这些技巧不是让考生炫技而是在底层开发和系统优化场景中确实常用考出来也很有区分度。5.3 开放性分析题如何在有限字数里展示多角度开放题通常没有标准答案比如让你“设计一个分布式限流方案”或者“如何优化一个高延迟页面”。这种题想拿高分关键是展示出工程思维先定义问题边界再提出至少两个可选方案说明对比的维度最后给出推荐结论并说明理由。有一个答题框架可以直接套用先明确问题场景数据量多大、并发多高、延迟要求多少。题目没给的话自己设定并说明。再列可选方案比如限流方案可以用固定窗口、滑动窗口、漏桶、令牌桶。分别说清实现思路和优缺点。最后给推荐选择结合前面的场景参数选择其中一个作为主方案说明为什么其他方案不合适。这种结构化回答的好处是阅卷老师即使和你思路不完全一样也能看出你是一个习惯系统思考的人而不是在零散地堆术语。简答题的字数不必追求特别长重点是逻辑顺畅、关键点覆盖到位。6. 实战时间轴与答题策略把会做的题全部做对6.1 做题顺序多数人适合的“两遍式”答卷每一套试卷都有送分题、普通题和压轴题。我见过不少同学特别喜欢跟压轴题死磕结果送分题反而因为时间不够而随便乱选。更稳健的模式是两遍式第一遍从头到尾快速过所有题遇到需要多想超过两分钟的题先标记跳过第二遍再集中解决标记题。选择题尤其适用这个方法因为拿不准的题先放下后面遇到其他题时可能得到提示也可能心态放松后一下子就想通了。编程题的处理我建议反过来看到的第一时间通读两遍题目要求然后先花两三分钟想清楚数据结构再动手。很多人急着写代码写到一半发现复杂度过不了又推倒重来反而更浪费时间。先想清楚要用的数据结构是数组、哈希表还是树往往比直接动手写更稳定。6.2 编程题通过率到底看什么笔试平台上的编程题通常用测试用例判定通过率不是只看核心思路对不对。所以提交之前要检查几个容易被隐藏用例击穿的场景边界条件数组为空、链表只有一个节点、输入为0或负数。数值溢出加法或乘法运算量大的题考虑是不是需要用long。重复元素题目没有说“无重复”就要假设可能有重复。时间复杂度数据量达到10^5以上时O(n^2)解法大概率超时。写代码时最好用注释写上核心思路一两句。笔试平台不会因为注释给分但如果你写一半思路乱了注释能帮你快速回到正确轨道。另外本地代码和在线平台的输入输出格式经常有细微差别建议考试前就用在线IDE跑一两个例子避免读入公式写错。6.3 考前一晚的复盘清单最后分享一个临考前用过的复盘清单都是A卷最容易涉及并且值得快速过一遍的点数组双指针、前缀和、原地删除、最大子数组。链表反转、快慢指针、合并、环形检测。二叉树递归与非递归遍历、层序、最近公共祖先。动态规划状态定义、初始化、转移方程、滚动数组优化。哈希与字符串字符计数、滑动窗口。C/C数组名退化为指针、sizeof、内存对齐、字节序。Java与equals、字符串拼接、类加载顺序、集合线程安全。操作系统进程线程、死锁四条件、页面置换、虚拟内存。网络TCP三次握手、TCP与UDP区别、HTTP状态码、HTTPS握手。时间分配先快扫全卷再集中攻克跳过的题。考前不需要再大量刷新题把上述每个点对应的一两道经典题重新想一遍思路比盲目刷题更有用。笔试不是竞赛它的核心目标是让基础扎实、思路清晰的人在有限时间内把能力稳定输出出来。我自己的体会是整套A卷真正拉开差距的地方往往不是最难的压轴题而是那些“看起来基础但藏了一两个坑”的题目。备考时多给自己出一点变化题多想想这道题如果换个条件我会不会做比单纯背答案要重要得多。