十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

蚂蚁集团2023秋招开发岗笔试复盘:题型解析与编程题思路

蚂蚁集团2023秋招开发岗笔试复盘:题型解析与编程题思路 2023年秋招季我在8月底投了蚂蚁集团开发岗9月中旬收到笔试邮件。说实话这封邮件来得比我预想的早——我本来以为像蚂蚁这种级别的公司简历筛选至少得卡上两周。当天晚上我就去翻了一圈往年笔试的帖子发现信息非常零散要么是刚考完的回忆版要么是求面经真正成体系的题型总结几乎没有。所以这次笔试结束后我趁着记忆还热乎把整场笔试从头到尾复盘了一遍。这篇东西适合正在准备大厂开发岗笔试、尤其是目标是蚂蚁这类业务复杂度高的公司的读者不管你是后端、客户端还是测开方向考察逻辑都相近值得花几分钟读完。1. 2023秋招笔试的基本盘平台、时长与题型构成1.1 投递与笔试通知的节奏先说时间线。我走的是官网统一投递没有内推码简历状态从已投递变成已处理大概花了5天。笔试邮件是挂在邮件系统里的标题写着蚂蚁集团2023校园招聘在线笔试邀请点进去会看到考试链接和截止时间。这里有个容易忽略的细节蚂蚁秋招笔试不是统一时间场次而是按批次的预约制。你可以在它给定的时间窗口里选一场比如周日下午和周三晚上各一场选完了再改会比较麻烦。选场次的时候建议不要选当天第一场。为什么大厂笔试题库通常会有几套平行卷第一场考完网上立刻会流出回忆版但不是让你去抄答案——而是能提前知道大概的考点密度和题型风格。像蚂蚁这种量级的公司题目重复率很低真正有价值的信息是它今年考了哪些方向是偏动态规划还是偏复杂模拟了解这个能帮你分配有限的复习时间。1.2 题型分布与计分规则蚂蚁开发岗笔试时长是90分钟整体结构分成两大部分30道选择题和4道编程题。这里说的选择题不同于行测而是纯技术选择题分单选和多选。多选是重灾区选错不得分、漏选得一半分这个规则直接决定了你的答题策略没把握的选项宁可少选不要赌。分值分布大致是这样题型数量每题分值小计单选题204分80分多选题106分60分编程题440-60分200分左右合计34-约340分编程题是按通过用例比例给分的不是AC了就满分、没AC就零分。这就意味着你哪怕只能过一部分用例也一定要把代码提交上去——空着和过了30%的用例得分差距很大。我后来跟几个同样参加了这场笔试的同学聊多数人的编程题是通过1到2道、剩下两道拿到部分分真正4道全AC的是极少数。1.3 赛码网平台的几个关键体验今年蚂蚁用的是赛码网不是牛客。第一次用赛码网的人可能会有点不习惯——它的编辑器比较朴素没有代码补全也没有本地调试窗口你写完代码只能通过编译报错来判断问题。这个体验和力扣差别很大力扣封装好了输入输出你只管写核心逻辑赛码网的题目需要你自己处理标准输入输出。平台支持的语言有Java、C、Python、Go我选的是Java。注意赛码网的Java版本偏老,不推荐使用var这类高版本特性能用基础语法尽量用基础语法避免编译报错浪费时间。2. 编程题实录四道题从签到到压轴的解题复盘编程题是这场笔试的胜负手。选择题大家差距不会太大真正把分数拉开的是编程题能AC几道。以下按我记忆中的题目还原思路和代码都是考后重新整理的版本复杂度分析和边界情况比考场上的更完整。2.1 回文串判断变体签到题也要注意输入细节第一题是热身的难度给定一个字符串只包含大小写字母和数字要求忽略大小写、忽略所有非字母数字字符后判断它是否是一个回文串。看起来很简单但通过率没有那么高原因出在输入处理上。字符串里可能包含空格和标点符号所以读取的时候要用nextLine()而不是next()否则字符串只读到第一个空格就断了。另外就是字符过滤的阶段必须跳过空格和标点再比较。我当时写的是双指针版本import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); String s sc.nextLine(); int left 0, right s.length() - 1; boolean flag true; while (left right) { while (left right !Character.isLetterOrDigit(s.charAt(left))) { left; } while (left right !Character.isLetterOrDigit(s.charAt(right))) { right--; } if (Character.toLowerCase(s.charAt(left)) ! Character.toLowerCase(s.charAt(right))) { flag false; break; } left; right--; } System.out.println(flag ? Y : N); } }注意输出格式要求是Y/N而不是true/false这种细节在白板做题时非常容易踩。我的经验是提交前先看一眼题目的输出样例严格按照样例的格式来。另外双指针的跳过逻辑里while循环的条件要写成left right防止指针越界——比如字符串全是空格或者全是特殊字符时不加这个条件就会数组越界。这道题真正想考察的不是回文判断本身而是字符串处理的基本功和边界思维。能一遍AC的人说明平时写代码对输入输出和边界条件有肌肉记忆。2.2 字符串消除游戏一道考栈的变形题第二题给定一个只包含小写字母的字符串重复执行删除所有相邻相同字符的操作直到字符串无法继续删除求最终字符串。举个例子abbaca经过一次删除后变成aaca再次删除后变成ca最终就是ca。这道题和力扣的删除字符串中的所有相邻重复项几乎一致但考察点是明确的栈的运用。你不需要真的反复扫描字符串那会退化到O(n^2)正确做法是遍历一次用栈维护当前未被消掉的字符序列遇到新字符时和栈顶比较相同就弹出不同就压入。import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); String s sc.nextLine(); StringBuilder stack new StringBuilder(); for (char c : s.toCharArray()) { if (stack.length() 0 stack.charAt(stack.length() - 1) c) { stack.deleteCharAt(stack.length() - 1); } else { stack.append(c); } } System.out.println(stack.toString()); } }这里用StringBuilder模拟栈比直接用StackCharacter更高效也不会有自动装箱的开销。deleteCharAt是O(1)的因为只操作尾部。一个容易漏掉的坑条件判断里要先检查stack.length() 0否则空栈时调用charAt会越界。另外这道题要求的是所有相邻相同字符不是连续相同字符保留一个——前者是aa删除后如果有aab会变成b后者会变成ab方向完全不同。看清楚题目的语义比背模板重要得多。2.3 网格最小路径和二维DP和一维优化的双重解法第三题是标准的动态规划给定一个m行n列的网格每个格子里有一个非负整数表示路径代价每次只能向右或向下移动求从左上角走到右下角的最小路径和。这种题相信大家都不陌生第一反应就是二维DPdp[i][j]表示从左上角走到(i,j)的最小代价转移方程为dp[i][j] min(dp[i-1][j], dp[i][j-1]) grid[i][j]。但考场上CPU占用比较高我不建议一上来就写int[][] dp new int[m][n]更好的是直接在一维数组上滚动更新import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); int m sc.nextInt(); int n sc.nextInt(); int[][] grid new int[m][n]; for (int i 0; i m; i) { for (int j 0; j n; j) { grid[i][j] sc.nextInt(); } } int[] dp new int[n]; dp[0] grid[0][0]; for (int j 1; j n; j) { dp[j] dp[j - 1] grid[0][j]; } for (int i 1; i m; i) { dp[0] grid[i][0]; for (int j 1; j n; j) { dp[j] Math.min(dp[j], dp[j - 1]) grid[i][j]; } } System.out.println(dp[n - 1]); } }一维优化后的dp[j]在更新前存的是上一行的值更新后是本行的值所以Math.min(dp[j], dp[j-1])恰好对应从上边来和从左边来两种选择不需要额外数组。这个写法理解了之后很多二维DP都可以照搬。另外输入里的m和n可能是10^3量级如果开二维数组可能面临内存压力滚动数组是实打实能救命的。这道题我大概花了8分钟处理完算是后面时间够用的原因之一。2.4 逆序对计数加难版归并排序在笔试中的价值第四题是真正的压轴题给定一个长度为n的数组a求满足i j且a[i] 2 * a[j]的数对数量n最大到10^5。由于a[i]的范围可能到int边界乘积运算中要小心溢出。这道题是逆序对计数的变形。经典的逆序对计数用归并排序可以在O(n log n)时间内完成这里多了个2 *的系数处理方式是在归并的过程中单独做一次统计当左半段的指针指向的元素a[i]大于2 * a[j]时说明左半段从i到mid的所有元素都满足条件计数加上mid - i 1。完整代码如下import java.util.Scanner; public class Main { private static long count 0; public static void main(String[] args) { Scanner sc new Scanner(System.in); int n sc.nextInt(); int[] arr new int[n]; for (int i 0; i n; i) { arr[i] sc.nextInt(); } mergeSort(arr, 0, n - 1); System.out.println(count); } private static void mergeSort(int[] a, int left, int right) { if (left right) return; int mid (left right) 1; mergeSort(a, left, mid); mergeSort(a, mid 1, right); // 统计满足 a[i] 2*a[j] 的数对 int i left, j mid 1; while (i mid j right) { if ((long) a[i] 2L * a[j]) { count mid - i 1; j; } else { i; } } // 归并排序的核心合并逻辑 int[] tmp new int[right - left 1]; int p left, q mid 1, idx 0; while (p mid q right) { if (a[p] a[q]) { tmp[idx] a[p]; } else { tmp[idx] a[q]; } } while (p mid) tmp[idx] a[p]; while (q right) tmp[idx] a[q]; System.arraycopy(tmp, 0, a, left, tmp.length); } }需要注意几点。第一count必须用long因为n10^5时数对数量接近5×10^9int装不下。第二比较时把a[i]和2L * a[j]都转成long避免乘法溢出导致判断错误。第三统计要放在合并之前因为合并会把左右数组打乱。这道题考场上我没能完整写对统计和合并的顺序一开始搞反了导致样例输出错误。后来冷静下来重新理了一遍逻辑才修正过来。复盘的时候我意识到这种题目其实是在考你对分治思想的熟练度不仅仅是会不会背归并排序模板。3. 选择题部分的知识点地图哪些分不该丢蚂蚁的30道选择题覆盖的范围很广对于目标明确是开发岗的候选人来说这个地图基本就是大厂技术面试的地基清单。我把自己能记起来的考点按模块整理出来方便你对照复习。3.1 Java基础与并发工具的考察密度Java相关选择题大概占了8道左右是选择题里占比最大的板块。考察方向集中在几个核心话题HashMap的底层实现链表转红黑树的阈值8和退化阈值6、扩容时的Rehash机制、为什么并发下会丢数据。ConcurrentHashMap的分段锁机制在JDK 8后改成了CAS加锁。有个多选题问的是哪些操作是线程安全的很多人会漏选computeIfAbsent因为这个方法在JDK 8里看起来像是原子操作实际上在特定条件下会有重算的坑。JVM内存区域堆、栈、方法区、程序计数器的职责划分一个典型的判断题是静态变量存放在堆上还是方法区。这个问题和JDK版本有关JDK 8的静态变量实例其实在堆中而不是多数人记忆里的永久代/方法区。垃圾回收可达性分析、GC Roots包括哪些对象、CMS和G1的停顿模型区别。当时有一道多选题让我印象很深它给出一段多线程代码问哪几种方式能保证线程安全。选项包括synchronized、volatile、AtomicInteger和ThreadLocal。这个问题的正确分类是synchronized和AtomicInteger可以保证原子性volatile只保证可见性ThreadLocal只做线程隔离——所以后两者单独用并不能保证复合操作的线程安全。这种题比单纯的八股文难一点它考的是工具的特性和适用边界复习的时候不能只记结论要理解场景。3.2 数据库原理从全局到中间件的考察数据库大概有5道题覆盖了索引、事务和分布式数据库三个方向。蚂蚁是OceanBase的主要贡献者所以笔试里出现分布式数据库相关的题目并不意外。B树索引为什么选择B树而不是B树或红黑树作为索引结构。核心答案在于B树的内节点不存储数据、每层能容纳更多键值树高更矮而且叶子节点通过链表串联适合范围查询。事务隔离级别读未提交、读已提交、可重复读、串行化以及MVCC在不同隔离级别下的实现差异。MySQL默认的可重复读如何通过间隙锁避免幻读这是经典考法。OceanBase相关有一道题问OceanBase的架构特点正确选项包括基于Paxos协议实现多副本一致性和支持完整的SQL事务能力。这类题如果你没有专门了解过基本只能靠常识推测但至少别选错单机数据库升级版这种明显错误的选项。这里想说一个备考策略复习数据库不要只盯MySQL大厂笔试越来越喜欢放一道自己核心数据库产品相关的题目的是筛选出真正对公司技术有了解的人。你可以不深入源码但至少要读一遍相关产品的技术白皮书把架构特点、一致性协议、适用场景记住。3.3 网络、操作系统与逻辑题的取舍网络和操作系统合起来大概8道题难度中等。网络部分重点在TCP三次握手、TIME_WAIT状态的作用、HTTP与HTTPS的握手差异以及HTTP/2多路复用的原理。有一道题问TIME_WAIT为什么需要存在正确选项是确保最后一个ACK能被对端收到和让旧连接上的延迟报文在网络中过期。后一个点很多人会漏掉——TIME_WAIT不只是为了重发ACK更是为了防旧连接报文干扰新连接。操作系统部分覆盖了进程调度先来先服务、短作业优先、时间片轮转、死锁的必要条件互斥、持有并等待、不可剥夺、循环等待以及虚拟内存的页面置换算法。其中一道多选问哪些情况会触发系统调用正确选项是fork()、read()和mmap()而普通的加减法运算不会触发系统调用。这类的区分点在于用户态能不能完成——凡是涉及资源分配或硬件访问的操作必须陷入内核。逻辑题大约有3道涉及概率计算和简单推理。比如一个经典的蒙提霍尔问题变体三扇门一扇后面有奖品你选择一扇后主持人打开一扇空门问你换不换。答案是换胜率从1/3提升到2/3。还有一道是两人轮流抛硬币先抛出正面的获胜求先手胜率这是一个等比数列求和问题结果是2/3。这类题平时看看经典概率题就行不需要专门刷。4. 答题节奏与平台问题踩过的坑和补救4.1 我的答题顺序与每部分耗时笔试90分钟我的时间分配是这样的选择题用了约28分钟第一道编程题8分钟第二道15分钟第三道8分钟第四道卡了将近20分钟最后检查和补交花了几分钟。复盘这个时间线最大的问题出在第四题上——我在统计逆序对的逻辑上绕了太久导致剩下检查的时间很紧。正确的做法应该是在第三题做完后先花1-2分钟把第四题通读一遍如果觉得一时间想不到解法就先跳过把前面所有代码再检查一遍比如输入输出格式、数组越界、long类型有没有用对然后再回来啃硬骨头。但当时我的心态是前三道这么顺第四道肯定也能啃下来结果反而挤占了检查时间。所以我的核心建议是绝不能让一道题占据超过25分钟的预算。一道编程题如果20分钟内没有完整的AC思路就果断降级为拿部分分策略——把暴力解法写上保证能过样例的小用例然后去确保其他题的稳健性。4.2 赛码网线上笔试的三个细节多组输入、JDK版本、编译环境赛码网的体验和其他在线笔试平台不太一样这里有几个真实存在的坑值得提前知晓。第一是输入输出。赛码网的题目模板通常已经帮你写好Scanner的读取逻辑但部分题目要求处理多组测试数据而不是单组。如果你的代码只读一组就返回后面的测试用例全部判错得分会非常难看。考场遇到这种题先用while(sc.hasNext())包一层不要担心读多了——判题系统只会按用例来截取。第二是JDK版本。赛码网的Java编译器版本偏旧var关键字、List.of()这些JDK 9的写法都无法编译。我在练习阶段就吃过一次亏后来学乖了笔试一律用最基础的ArrayList、HashMap和传统for循环花哨语法一个不碰。第三是本地IDE与线上环境的差异。本地运行正常不代表线上能过常见原因包括包名问题OJ要求无包名、类名问题必须是Main、还有不可见的制表符或中文字符混进了代码。建议提交前把所有代码全选后统一改成半角符号如果编译报错信息看不懂就检查有没有全角逗号或括号。4.3 编程题边界条件与数据类型的小结从这次笔试的四个编程题来看边界条件考察非常集中我整理了一个自查清单空输入数组长度为0时程序不能崩溃要返回默认值。单元素输入有些DP题的边界状态只有一行或一列把初始化写对。输入包含空格字符串题一律用nextLine()。int溢出涉及总和、比较、乘法的地方先用long或者long强转。数组越界双指针和多指针循环里先检查left right或i n再访问元素。这个清单是我在复盘时从四道题里提炼出来的。如果你正在刷题阶段可以建立一个自己的提交前检查清单每次提交前过一遍能大幅减少低级的WAWrong Answer和RERuntime Error。5. 笔试题的横向对比与后续准备5.1 蚂蚁笔试与同期大厂笔试的方向差异秋招期间我除了蚂蚁还参加了另外几家大厂的笔试对比下来能明显感觉到蚂蚁出题风格的特征。蚂蚁开发岗的笔试整体偏重算法和数据结构的扎实度选择题维度覆盖很全面而编程题的难度梯度非常明显——前两题基本是给基础扎实的人送分后两题直接拉开区分度。相比之下拼多多的笔试更为刁钻题目描述冗长经常带着业务场景的壳子读题成本更高更需要从文字中抽离出数学模型的能力。微众银行的数据分析岗笔试则完全不同以SQL和概率统计为主对于算法题的要求相对较低所以如果你同时投了不同类型的大厂岗位复习方向要有所侧重不能一套题单打天下。5.2 笔试结束后应当立即做的三件事很多人的习惯是笔试一结束就解放了但我的经验是笔试结束后的15分钟比考前刷题更能带来成长。趁记忆还热乎应该立刻做三件事。第一把四道编程题的题目描述、你当时的思路和卡住的点位用备忘录快速记录下来。不用写得很完整你自己的语言就够了重点是卡在哪一步——这个信息在后面的复盘里价值极高。第二迅速搜索网上是否已有当场的讨论帖或回忆版题解。比对别人的AC思路和你的差异你会立刻发现自己漏了哪种简化方法。比如第四道逆序对题我当时绕了很久后来看到讨论帖里提到可以用树状数组加离散化也能AC虽然归并排序也是正解但两种思路点出的是不同的训练方向。第三记录下自己每道题的时间分配。笔试结束后回忆一下选择题30分钟、编程第一题8分钟、第二题18分钟、第三题10分钟、第四题25分钟这样精确到分钟的记录。连续记录三场后你就能找到自己的节奏模式——到底是选择太慢还是难题卡太久。面试官在面评里会看到你的笔试分数和答题用时编程题的AC数量和代码提交次数都是重要参考。提交次数过多比如反复提交同样错误的代码会给面试官代码一次性正确率低的不良印象。所以与其着急提交不如在本地多做几组自测用例确保稳了再提交。5.3 从笔试反馈倒推复习重心如果你的选择题正确率低于70%说明计算机基础存在明显知识盲区这会直接影响后续的面试。选择题覆盖的内容在面试中会变成讲一讲HashMap的扩容过程深挖一下MVCC这类问题。笔试筛选不是刷掉就完了它是一份最真实的能力体检报告。我的做法是用Excel建了一张表把每场笔试的选择题错题按Java基础、并发、JVM、数据库、网络、操作系统、概率题分类统计每个分类的错误率。刷到第五场时回看数据如果发现自己数据库类的错误率一直居高不下就去针对性补。这种基于自己真实数据的精准复习比盲目刷题效率高得多。编程题方面如果蚂蚁的四道题只能AC一道说明你的算法训练还停留在会做模板题的阶段。这时候不要着急投下一家应该用至少两周时间集中补一下二叉树的遍历与层级处理、常见的DP模型背包、路径、最长递增子序列、并查集、单调栈、归并排序变体这些都是大厂笔试的高频考法。力扣热题HOT 100里的前60题值得反复刷不是做完就行而是做到能讲清楚复杂度、能默写关键代码。笔试面试这个环节我个人的感受是比起考前熬夜刷题日常的积累和稳定的心态更能决定你的发挥。蚂蚁这场笔试之后我最大的收获不是AC了几道题而是对赛码网平台的熟悉程度以及对自己的技术短板有了一个清晰的认知。如果你正在备考希望你把这些经验用在练习里到了真正笔试那天你会发现——未知的恐惧没了剩下的都是可以做好的题目。
返回列表