服务端开发实习生笔试高频考点:集合、并发、索引与算法全复盘
前阵子整理旧笔记本翻出一份自己当年准备小米春季实习生招聘时整理的笔记。2018年那场服务端开发工程师的笔试到现在回头看其实很能代表国内互联网公司对这个岗位实习生的考察逻辑。不少知识点比如Java集合的底层实现、并发工具的使用、MySQL索引失效的场景、TCP协议的细节在今天的大厂校招笔试里依然是高频考点。这篇文章就把我记忆中的题目类型、背后的考察点以及我自己复盘的心得整理出来给正在准备服务端开发实习岗位的同学做个参考。1. 服务端实习生笔试到底在考什么1.1 为什么笔试题目会这样设计先聊一个很多人会忽略的问题公司招实习生笔试到底想筛什么你可能会觉得是筛选“会做题的人”但我后来参与过日常的校招辅助工作看了不少笔试卷子发现出题人的核心逻辑其实很一致——在短时间内考察你的基础是否扎实、思维是否清晰、代码习惯是否合格。实习生和正式员工不一样正式员工你还可以指望他有项目经验、有领域积累但实习生普遍是还没毕业的学生项目经历大多比较单薄。这种情况下笔试是性价比最高的筛选方式用一套题快速判断候选人有没有把计算机基础学明白。所以你会发现服务端开发的笔试题往往覆盖面特别广从Java语法到操作系统从网络协议到数据库索引从算法到SQL什么都要考一点。这不是出题人故意刁难你而是这个岗位的日常工作确实需要这些知识。服务端要处理请求、操作存储、排查性能问题、设计接口每一环都建立在计算机基础之上。再说说为什么实习生笔试的算法题通常比正式社招简单。社招看重的是你能否解决复杂业务问题而实习生更多看潜力和学习速度所以算法题不会太偏门基本集中在链表、二叉树、动态规划入门、字符串处理这些经典题型。你要做的不是刷几千道题而是把常考类型练熟形成条件反射。1.2 知识版图拆解一张表看清考察范围小米这场笔试是典型的“选择题编程题”组合其中选择题占大头编程题一般两到三道。根据我自己的回忆和后来整理的题目复盘服务端开发方向的知识版图可以拆成下面这几个模块。知识模块常见考察点题目形态Java基础String、集合源码、异常、泛型、反射选择题并发编程synchronized、volatile、线程池、ThreadLocal选择题JVM内存区域、垃圾回收、类加载机制选择题计算机网络TCP/UDP、HTTP、DNS、三次握手四次挥手选择题操作系统进程线程、内存管理、Linux命令选择题数据库索引、事务隔离级别、SQL编写选择SQL题缓存与中间件Redis数据结构、缓存穿透/击穿/雪崩选择题算法与数据结构链表、二叉树、动态规划、字符串编程题这张表里的每一行基本对应服务端日常开发中会碰到的问题。比如说并发编程你写接口时总得考虑多线程安全吧数据库更是躲不开的几乎所有业务都要跟MySQL打交道。所以不要觉得笔试是在刁难人它其实是在模拟一个服务端工程师最基础的知识储备。1.3 试题难度分布基础、进阶、压轴的比例不同公司出题风格略有差别但总体难度分布大致可以参考“60%-25%-15%”这个比例。大约六成题目是基础题只要你认真学过基本能答出来比如“ArrayList和LinkedList的区别”“TCP三次握手的流程”“HashMap的put过程”。这部分是为了保证筛选的公平性让人人都能上手。剩下两成半是进阶题需要你真正理解原理而不是背结论。比如“为什么JDK 1.8要把HashMap在链表长度超过8时转成红黑树”“ThreadLocal为什么可能内存泄漏”“MySQL的联合索引在什么情况下会失效”。这类题目考察的是你有没有深入思考过常见技术方案背后的权衡。最后的一成半是压轴题通常出现在编程题里比如设计一个LRU缓存、手写一个线程安全的单例、或者一道需要优化的动态规划。这类题目没那么好拿分但也不是完全做不出来。理解了难度分布你备考时就知道时间该往哪里花先确保基础题不丢分再努力吃透进阶题压轴题能写多少写多少。2. 核心细节解析与实操要点几类必考题型2.1 Java基础与集合源码选择题里的重头戏服务端开发岗的笔试Java方向的题目比重通常是最高的而且很多考点喜欢往集合源码上靠。原因很简单集合是日常写代码用到最多的工具类你连它的底层实现都不清楚面试官很难相信你能写出高性能的程序。先说说ArrayList和LinkedList。这是最经典的送分题但很多人答得不够完整。ArrayList底层是数组查询快、插入慢扩容时默认增加原来容量的50%也就是1.5倍LinkedList底层是双向链表插入删除快在已知节点的情况下但随机访问慢。笔试里还会进一步问ArrayList插入元素的时间复杂度是多少这里要分情况——在尾部插入平均是O(1)但在中间插入需要移动元素是O(n)。LinkedList在头部插入是O(1)在尾部插入如果是双向链表也维护了尾指针也是O(1)但如果要在中间位置按索引插入找节点就要O(n)。再说HashMap这是Java面试的“常青树”笔试也爱考。核心知识点包括put操作的过程、hash冲突怎么解决、什么时候扩容、什么时候转红黑树。JDK 1.8之后HashMap在链表长度达到8且数组长度达到64时会把链表转成红黑树目的是把查询时间从O(n)降为O(log n)。为什么阈值选8这是泊松分布算出来的在负载因子0.75的情况下链表长度达到8的概率已经非常低选这个值既能避免红黑树频繁转换带来的开销又能保证极端情况下性能不会太差。这些细节选择里经常出现需要理解记忆。还有String相关的题目。String为什么要设计成不可变因为不可变对象天然线程安全字符串常量池也依赖这一点String和StringBuilder、StringBuffer的区别也是高频题。equals和hashCode的约定也是必考重写equals就一定要重写hashCode否则HashMap里可能出现“两个对象相等但hashCode不同”的bug。这些属于Java基础里最朴素的常识却是每次笔试都会出现的“老朋友”。2.2 并发编程笔试里的送分与送命并存并发是服务端开发的核心话题也是笔试的必考模块。这里面的题目两极分化比较严重基础题问“synchronized和ReentrantLock的区别”“volatile能不能保证原子性”进阶题问“线程池的拒绝策略有哪几种分别适合什么场景”。前者是送分后者才是区分度所在。synchronized和ReentrantLock的区别建议从几个维度回答一个是JVM层面内置的锁一个是API层面的锁synchronized不需要手动释放锁ReentrantLock需要手动lock/unlock并建议配合try-finallysynchronized不支持中断ReentrantLock支持lockInterruptiblyReentrantLock还支持公平锁和非公平锁切换synchronized只能是非公平锁。这些点要答全但别死记硬背想一下JDK为什么要提供两套锁机制自然就理解了。volatile是另一个高频考点。它保证可见性和有序性但不保证原子性。很多人把volatile等价于“线程安全”这是大错特错。典型例子是i操作即使变量被volatile修饰多线程下依然会出现数据不一致因为i不是原子操作包含读、改、写三步。那volatile有什么用典型的应用场景是状态标志位一个线程修改flag另一个线程读flag用volatile修饰可以保证修改立刻对其他线程可见再加上禁止指令重排可以保证DCL单例的正确性。线程池这块要掌握ThreadPoolExecutor的七个参数核心线程数、最大线程数、空闲线程存活时间、存活时间单位、任务队列、线程工厂、拒绝策略。拒绝策略有四种AbortPolicy直接抛异常、CallerRunsPolicy让调用线程执行、DiscardPolicy静默丢弃、DiscardOldestPolicy丢弃最老任务。笔试常考“任务提交顺序”先核心线程再任务队列再最大线程数最后走拒绝策略。这个顺序一定要记牢很多人会以为先开满最大线程再进队列实际上恰恰相反。ThreadLocal也是个容易出题的知识点。它通过每个线程保存自己的变量副本实现线程隔离但使用不当会造成内存泄漏。原因是ThreadLocalMap的Entry继承了WeakReferencekey是弱引用value是强引用。当ThreadLocal对象没有外部强引用时key会被回收但value还在这就有了一条从Thread到ThreadLocalMap再到value的强引用链导致value无法回收。所以规范做法是在finally块里调用remove方法。这个考点很细但在笔试里出现概率不低因为服务端踩过这个坑的人太多了。2.3 网络与操作系统笔试的纯背诵题怎么拿满分网络和操作系统算是笔试里的“背诵模块”知识点固定、答案明确只要认真理解过不太容易丢分。但很多人吃亏在背得不完整比如TCP三次握手能说出来四次挥手却说不清楚或者知道TIME_WAIT存在却说不清为什么要等待2MSL。TCP三次握手的关键不是背“SYN、SYNACK、ACK”这三个词而是理解为什么需要三次。三次握手的目的至少有两个确认双方的发送和接收能力都正常同步双方的初始序列号。第一次握手服务端确认客户端发送能力正常第二次握手客户端确认自己发送和接收都正常也确认服务端发送接收正常第三次握手服务端确认客户端接收能力正常。你把这个逻辑理清楚了就算题目换个说法考你也能答上来。四次挥手和TIME_WAIT是网络题里最爱出细节的点。先说主动关闭方为什么需要TIME_WAIT一是为了保证最后一个ACK能到达对端如果丢失对端会重发FIN主动关闭方需要能再次回ACK二是为了让旧连接的报文段在网络中消失避免影响新连接。等2MSL是为了确保所有报文都消失。笔试里可能会问如果服务端处理大量短连接TIME_WAIT过多怎么办常见的优化方案有开启tcp_tw_reuse、调整tcp_max_tw_buckets等但你要知道TIME_WAIT本身是设计如此过度优化反而可能引入问题。操作系统这边进程和线程的区别是必考。核心考点包括进程是资源分配的基本单位线程是CPU调度的基本单位同一进程的线程共享内存空间和文件描述符但进程之间地址空间相互独立线程切换比进程切换开销小因为不需要切换地址空间。还会问进程间通信的方式管道、消息队列、共享内存、信号量、Socket。这里要注意经常有同学把线程同步的方式和进程间通信的方式混在一起回答时最好分开谈。Linux命令也是笔试常客。比如查看端口占用用netstat -tlnp或ss -tlnp查看进程CPU和内存占用用top查看磁盘空间用df -h查看内存用free -m查找日志文件中的关键字可以用grep按列切割用awk排序用sort。这些命令在笔试选择里会零散出现建议每题都当成“以后排障真会用到”来记别死记。我在实际工作里排查线上问题时最先用的也就是这几个命令。2.4 数据库与缓存面试官最看重的工程素养数据库内容是服务端开发笔试里最有“工程感”的部分也是最容易拉开差距的地方。很多选择题会围绕MySQL的索引展开编程题里往往还有一道SQL题。这些题目的考察重点不是你会不会写CRUD而是懂不懂索引和事务。先讲索引。MySQL InnoDB引擎用的是B树而不是B树或哈希索引原因要讲清楚B树把所有数据都存放在叶子节点叶子节点通过指针串联非常适合范围查询和顺序扫描哈希索引只支持等值查询不支持范围查询所以即使查询快也敌不过B树的全能。联合索引最左前缀原则也是个高频考点比如你建了(a, b, c)联合索引那么查询条件里只有a、a和b、a和b和c能用到索引只有b或c就用不上。索引失效的常见场景包括对索引列使用函数、隐式类型转换、like %xxx前置通配符、or条件里有非索引列。这些一定要记清楚实际工作中排查慢SQL经常用到。事务隔离级别也是个必考点。MySQL默认的隔离级别是Repeatable Read可重复读但它通过MVCC解决了部分幻读问题。四种隔离级别分别是读未提交、读已提交、可重复读、串行化分别解决脏读、不可重复读、幻读的问题。串行化是最高级别但性能最差。笔试里常见的问法是“在可重复读隔离级别下是否会出现幻读为什么”答案是在MVCC下普通的快照读不会出现幻读但在当前读select ... for update下可重复读依然可能出现幻读InnoDB是通过间隙锁来进一步避免的。这个细节能把很多人考倒。Redis缓存这块最常考的是缓存穿透、缓存击穿、缓存雪崩三兄弟。穿透是查一个不存在的key每次都落到数据库解决方法是布隆过滤器或缓存空值击穿是某个热点key过期大量请求同时打向数据库解决办法是互斥锁或永不过期加逻辑过期雪崩是大批key同时失效解决办法是过期时间加随机值、热点数据不过期、做多级缓存。选择题里一般会给你一个场景让你判断属于哪类问题以及该怎么解决这需要你把三个概念区分得特别清晰。2.5 算法与数据结构三种常考类型要练到形成肌肉记忆算法编程题是笔试的重头戏分值最高也是大家最焦虑的部分。但服务端实习生的算法题难度其实就集中在三种类型链表类、树类、动态规划入门类。把这三类练到能默写绝大多数笔试都能应对。链表题里面反转链表是最经典的没有之一。迭代版要处理好pre、cur、next三个指针递归版要注意递归返回的节点。环形链表检测可以用快慢指针。合并两个有序链表可以用迭代或者递归思路都很直接。这一类题目的关键是画图在纸上把指针关系画清楚了代码基本不会写错。笔试时如果在线IDE不方便画图我习惯先在草稿纸上模拟一遍再下笔。二叉树题目里前中后序遍历的递归写法和迭代写法都要会层次遍历要会用队列做。最近公共祖先LCA是高频题递归解法思路很简洁如果root是null就返回null如果root等于p或q就返回root然后递归找左子树和右子树两边都不为空说明root就是LCA否则返回非空的那一边。这个解法代码只有十几行但理解起来需要一点递归思维建议亲手写三遍以上。动态规划属于看起来难、实际有套路的题型。爬楼梯、斐波那契、最大子序和、零钱兑换都是入门经典。关键步骤是定义dp数组、找状态转移方程、确定初始化和遍历顺序。比如零钱兑换问题是求凑出amount最少需要多少枚硬币dp[i]表示凑出金额i的最小硬币数状态转移就是dp[i] min(dp[i], dp[i-coin] 1)。笔试时如果时间紧张可以先写暴力递归再尝试加一个备忘录剪枝至少能拿到一部分分。还有一种容易被忽略的题型是栈和队列相关的题比如括号匹配、最小栈、用两个栈实现队列。这类题目代码短、思路清晰很适合在编程题里作为第二题出现。我备考时把这几类题目都整理成模板考前看一遍心理压力小很多。3. 实操过程与核心环节实现从一道题剖析完整答题策略3.1 先审题再动手我在笔试里踩过的看题误区很多人笔试翻车不是不会写而是没看清题。我自己就吃过亏。有一道算法题题目描述很长核心是反转链表但限定条件写得很隐蔽链表长度可能为0且空间复杂度要求O(1)。我一看“反转链表”立刻开始写写完了直接提交结果用例没过。后来冷静一看发现我用了递归写法递归栈的深度算作O(n)空间不符合题目的空间复杂度要求而且也没考虑空链表的情况。这种丢分最冤枉。吃一堑长一智后来我养成一个习惯拿到题目先花一到两分钟把题目读完圈出关键词。重点关注三个方面输入范围会不会是空数组、链表会不会有环、复杂度要求能不能用额外空间、时间要求多严、输出格式返回链表头还是数组、要打印还是返回。不要小看这一两分钟它能帮你避开至少三分之一的坑。3.2 编程题实战从读题到AC的完整思考过程这里拿一道很典型又不难的题来拆解反转一个单链表。题目描述是“输入一个链表反转链表后返回新链表的头节点”。很多人能写出代码但没想清楚每一步在做什么。我拿到题会先在草稿纸上画一个三节点的链表1 - 2 - 3 - null。目标变成3 - 2 - 1 - null。迭代的思路是维护三个指针pre指向当前节点的前一个节点cur指向当前节点next指向下一个节点。每一步把cur.next指向pre然后把pre和cur整体右移。核心代码如下public ListNode reverseList(ListNode head) { ListNode pre null; ListNode cur head; while (cur ! null) { ListNode next cur.next; // 先保存下一个节点防止指针反转后丢失 cur.next pre; // 当前节点指向前一个节点 pre cur; // pre右移 cur next; // cur右移 } return pre; // 循环结束时pre就是原链表的尾节点也就是新链表的头节点 }这段代码的边界点在哪里如果链表为空cur一开始就是nullwhile循环不执行直接返回pre也就是null正确。如果链表只有一个节点cur.next为null执行完循环返回该节点也正确。空间复杂度O(1)时间复杂度O(n)全部符合要求。这种写法背下来遇到变体题也能灵活调整。再拿一道稍微进阶的题目设计一个LRU缓存机制要求get和put操作的时间复杂度都是O(1)。这是很多大厂笔试的常客因为它考察的是你是否会用合适的数据结构组合。get要O(1)说明得有哈希表put要维护访问顺序说明得有一个能快速删除和插入的双向链表。两者结合就是“HashMap 双向链表”的经典结构。在Java里可以直接继承LinkedHashMap实现但笔试更希望看到你手写底层结构。用LinkedHashMap的实现方式如下class LRUCache { private final int capacity; private final LinkedHashMapInteger, Integer map; public LRUCache(int capacity) { this.capacity capacity; // accessOrdertrue表示按访问顺序排序false表示按插入顺序 this.map new LinkedHashMap(capacity, 0.75f, true); } public int get(int key) { return map.getOrDefault(key, -1); } public void put(int key, int value) { map.put(key, value); if (map.size() capacity) { // 超出容量时删除最久未访问的节点即链表头部 int oldestKey map.keySet().iterator().next(); map.remove(oldestKey); } } }笔试里用LinkedHashMap能很快通过但面试环节如果被追问“为什么LinkedHashMap能实现LRU”你得能说清楚accessOrder字段的含义以及双向链表的节点在访问时会被移动到尾部。所以平时训练时我会建议你手写一遍HashMap加双向链表的版本那才是真正的理解。3.3 数据库题手写SQL怎么避免低级错误笔试的SQL题一般不会太难大多是单表查询加一个聚合或者两张表关联查。但每年都有很多人在SQL题上翻车因为平时写代码用ORM太多手写SQL反而生疏了。我印象里小米笔试有一道类似的题目有员工表和部门表查询每个部门工资最高的员工姓名和工资。这种题第一反应是“先按部门分组再取最大值”但直接group by会出错因为分组后你没法拿到工资最高的那条记录的完整信息。正确思路是先用子查询查出每个部门的最高工资再和员工表关联。SELECT d.name AS dept_name, e.name AS emp_name, e.salary FROM employee e JOIN dept d ON e.dept_id d.id JOIN ( SELECT dept_id, MAX(salary) AS max_salary FROM employee GROUP BY dept_id ) t ON e.dept_id t.dept_id AND e.salary t.max_salary;这个SQL里的核心就是最后那个子查询t它把每个部门的最高工资算出来然后通过“部门相同且工资等于最高工资”两个条件关联回原表。写SQL的一定要注意ON条件不能只写部门相等一定要加上工资相等否则会查出同一部门所有员工都和最高工资关联结果就是错的。还有如果工资最高的员工有多个这个写法会全部查出来这通常是符合要求的。写完后我习惯再检查一遍字段名、表名有没有拼错以及JOIN的方向是不是还有遗漏。3.4 提交前的自检清单编程题写完不要急着提交我给自己定了一份自检清单每次笔试都按这个过一遍输入为空、长度为1的极端情况有没有处理数组访问有没有可能出现越界链表的指针有没有可能为空数值相加或相乘会不会溢出需不需要换成long时间复杂度和空间复杂度是否符合题目要求有没有在代码里留了调试用的System.out.println没删方法签名和变量命名是否符合题意类名是不是Main或题目指定的名字这份清单看着简单但能拦住大部分低级错误。我的经验是多花三分钟自检通常比多写一道不完整的题拿到的分更多。4. 常见问题与排查技巧实录笔试翻车点复盘4.1 时间分配失败别在前面的选择题上恋战笔试时间通常是一个半小时到两个小时看起来不短但题目量并不小。选择题多且碎如果每一题都反复纠结很容易陷入“前面花费太多、后面编程题没时间”的困境。我身边好几个同学都是挂在时间分配上选择题做了五十分钟编程题只剩二十分钟最后草草提交。我自己的建议是拿到试卷先花两分钟整体浏览一遍心里有底。选择题遇到拿不准的先标记跳过别在一道不确定的题上耗超过三分钟。编程题先做自己最擅长的把稳拿的分拿到手。时间分配可以大致按“选择题40分钟、编程题70分钟、SQL题10分钟”来规划但这只是一个参考具体还是看试卷结构。优先保证编程题有充足时间因为一道编程题的分数往往抵好几道选择题。4.2 编程题不通过大多数时候是这几种原因如果你笔试完发现编程题用例没过先别急着怀疑题目错了大概率是代码本身有坑。根据我的观察最常见的几类问题数组越界和空指针。这是新手最容易犯的错误。比如遍历数组时用了i nums.length或者访问链表的next之前没判断是否为空。这类错误编译器不会提示运行到特定输入才暴露排查起来很费时间。解决办法只有一个写循环之前先想好边界条件。死循环。链表反转时忘了更新指针、二分查找时left和right没移动、while循环条件写错都可能导致死循环。在线编译器通常有超时限制一旦超时就会判错。我建议代码里避免while(true)除非你非常确定循环里一定有break路径。超时。这属于算法复杂度不够。比如一道题数据范围是10^5你写了O(n^2)的双重循环大概率超时。笔试系统对时间卡的比较严所以写代码前得先估算复杂度。一般经验是10^6的数据量用O(n)或O(n log n)10^4以下才敢用O(n^2)。输出格式错误。这种最冤。题目要求输出“NO”你写成了“No”要求每个结果占一行你全打在一行要求保留两位小数你直接输出整数。这些细节在题目描述里通常有说明提交前一定要回头核对一遍。4.3 容易被忽略的笔试环境问题除了代码本身笔试环境也有不少坑这些属于“非技术性失误”但同样致命。我那次笔试就遇到过摄像头问题人脸识别一直过不去折腾了快十分钟才进入考试界面心态直接受影响。有几点值得注意笔试前至少提前半小时进入系统测试摄像头、麦克风、浏览器兼容性。尽量用Chrome或官方指定的浏览器别用一些开着广告插件的浏览器可能导致页面崩溃。代码编辑器的自动保存功能不一定可靠我习惯写一段就本地复制一份到记事本。还有注意考试过程中不要切出考试页面太多次有些系统会检测并记录切屏行为次数多了可能被判违规。虽然这个规定本意是防作弊但有时候只是系统的小弹窗也会被误判所以在考试前把无关软件尽量关掉会提醒弹窗的聊天工具也先忽略。4.4 笔试之后的复盘比分数更重要笔试结束后无论自我感觉是好是坏我强烈建议你做一次系统的复盘。这不是说要把题目背下来而是把每一道错题当作一次查缺补漏的机会。第一步把记忆中的选择题考点逐条列出来不管做对做错都去把相关知识点完整过一遍。比如“联合索引为什么最左前缀”你先看书理解再自己讲一遍讲不出来就再看一遍。第二步编程题全部再写一遍直到能不看答案写出来。我当时的习惯是每一道笔试编程题都在本地IDE重新实现测试各种边界输入然后写一篇简短的解题笔记。第三步把这次暴露出来的知识盲区记到自己的复习清单里和之前整理的面试题合并形成一本越来越厚的“错题本”。这套复盘方法听起来有点笨但效果特别好。很多人笔试做完就丢下次面试遇到同样的题还是不会白白浪费了真题资源。笔试的分数只是敲门砖真正对你有长期价值的是复盘过程中重新梳理的知识体系。4.5 备考时间短先抓这三个重点如果你距离笔试只剩一周时间不够全部细致复习我给你一个优先级建议。第一优先级是算法和数据结构每天至少刷三道经典题重点练反转链表、二叉树遍历、爬楼梯这类高频模板题。第二优先级是Java基础和并发这两块内容多但考得浅把集合、HashMap、线程池、volatile这些核心概念过一遍能答出选择题就行。第三优先级是数据库的索引和SQL重点看联合索引、索引失效场景再亲手写几道关联查询。反过来网络和操作系统如果时间不够可以先挑最经典的三次握手、四次挥手、进程线程区别、Linux常用命令来背剩下的内容等过了笔试再慢慢补。这样安排的核心思路是让自己在有限时间内拿到最大分值把基础题做对编程题写出一题就已经超过不少考生了。我个人在实际操作中的体会是这类笔试并不可怕它考察的内容其实都非常“正统”只要你把基础概念理解到位再配上一点点做题技巧完全能应对。尤其是服务端开发这个方向所有的考点都围绕着一个核心你有没有能力在生产环境里写出稳定、高效的代码。带着这个视角去备考你会发现自己不是单纯在刷题而是在为一个真正的工程师角色做准备。最后再分享一个小技巧笔试前一天的晚上不要再去钻研偏题难题把总结好的知识点清单、经典题模板翻一遍早点睡觉。考试时的精力远比考前多学一个小时更重要。祝准备笔试的同学都能拿到心仪的实习offer。