每年春招都是一场硬仗,携程作为OTA行业的老牌大厂,技术岗笔试的含金量和筛选力度一直都挺在线的。2023年这批技术通用岗的第二批笔试,我完整跟了下来,也和身边几个拿了面邀的同学对了下题。今天不聊虚的,直接把这批笔试的题型分布、考点细节、编程题的解题思路,以及我在准备和复盘过程中踩过的坑,一次性整理清楚。不管是准备秋招还是备战下一轮春招,这份拆解都能帮你少走不少弯路。
1. 这批笔试在考什么:题型结构与出题逻辑
1.1 整体结构:客观题加编程题是标配
携程的春招技术岗笔试,通常是在牛客网或者赛码网这种在线评测系统上完成,时间一般是90到120分钟。2023年这批通用岗的卷子,整体结构非常清晰,分为两大块:一块是客观选择题,一块是编程题。
客观题部分,数量大概在20到30道之间,覆盖的知识面很广,包括计算机网络、操作系统、数据库、Java或C++语言特性、数据结构基础,偶尔还会有一两道智力题或者逻辑推理题。这部分拼的是基础扎不扎实,没有什么取巧的空间。
编程题部分,通常是2到3道,难度梯度比较明显。第一题基本是送分题,考察基本语法和简单逻辑;第二题开始上强度,会涉及到常见的数据结构和算法,比如动态规划、贪心、DFS/BFS;第三题就是拉开差距的压轴题,往往需要综合运用多种技巧,而且对时间复杂度的要求很苛刻。我印象里,这批笔试的压轴题是一道结合了排序和双指针的题目,表面上看起来是模拟题,但如果不做优化,直接暴力求解的话,数据量一大必超时。
1.2 出题人到底想筛什么人
从这批笔试的题目设置来看,携程的出题思路很明确:它不想招一个只会背八股文的人,也不想招一个只会刷题但不懂工程的人。它想筛的是那种基础扎实、思维敏捷、而且能在有限时间内把思路转化成代码的人。
先说基础扎实。选择题里那些关于TCP三次握手、进程与线程区别、数据库索引失效场景的题目,就是在检验你大学四年有没有认真听课。这些知识在平时开发中可能不会天天用到,但它们是计算机学科的基石。如果你这些题错得太多,面试官会怀疑你的专业底子。
再说思维敏捷。编程题的时间限制很严格,比如第一题给你10分钟,第二题给你25分钟,第三题给你40分钟。这就要求你拿到题目后,能快速识别出题人的考察意图。是考哈希表去重?还是考前缀和优化?还是考二分查找边界?这种"题目翻译能力"是刷题刷出来的手感,没法靠临时抱佛脚。
注意:携程的笔试系统支持本地IDE调试,这点很友好。但要注意,提交时的代码必须是完整可运行的,不要只写一个函数体就交,系统是用测试用例来跑全量代码的。
2. 知识考点逐项拆解:哪些分必须拿
2.1 数据结构与算法:重点永远是"出镜率最高的几个"
如果你翻看携程历年笔试题,会发现数据结构与算法的考察范围其实很固定,并没有太多偏题怪题。
数组和链表是最基础的。笔试里经常会给你一个场景,比如"LRU缓存",表面上是设计题,本质上是考察你有没有理解数组和链表各自的优缺点——数组随机访问快但插入删除慢,链表插入删除快但随机访问慢,而LRU恰好需要兼顾两边的优势,所以要用哈希表加双向链表。这类题目在携程的笔试里出现过不止一次,值得重点准备。
栈和队列的考察点往往和"单调性"绑定。比如"接雨水"、"柱状图中最大的矩形",看起来很难,但核心就一句话:用单调栈维护一个递增或递减的序列,在入栈和出栈的时候做计算。我备考时把单调栈的几种经典题型都过了一遍,笔试时遇到类似题目,思路很快就有了,代码写起来也顺手。
二叉树的题目是笔试的常客。层序遍历、前中后序遍历(递归和非递归版本都要会)、最近公共祖先、二叉搜索树的合法性判断,这些就是高频中的高频。备考时我建议你把这些题的模板代码练到肌肉记忆的程度,因为笔试时间紧,真到了考场上,你没有时间现场推演递归流程。
哈希表、动态规划、贪心算法,这三块是拉开分数的关键。哈希表考的是"空间换时间"的思维,动态规划考的是状态定义和转移方程的推导,贪心考的是敏锐的直觉和严谨的证明。我个人的经验是,动态规划最怕"想当然",你一定要在纸上先举几个例子验证一下转移方程的正确性,再动手写代码,否则很容易代码写到一半发现状态转移错了,白白浪费时间。
2.2 计算机网络与操作系统:选择题的主战场
客观题里,计算机网络和操作系统的占比相当大,几乎能占到选择题总数的一半。这块内容没什么巧劲,全靠平时积累和考前突击记忆。
计算机网络,重点看TCP/IP协议栈。TCP的三次握手和四次挥手是必考的,而且会考得很细,比如SYN flood攻击的原理、TIME_WAIT状态为什么要等待2MSL。HTTP相关的知识点也要注意,携程作为互联网公司,对HTTP协议的状态码、请求方法、缓存机制(强缓存和协商缓存)的考察频率很高。还有DNS解析过程、HTTP和HTTPS的区别,这些都要能说清楚。
操作系统,进程与线程的区别是送分题,但考点会延伸到线程模型、协程的优势、死锁的四个必要条件(互斥、占有并等待、非抢占、循环等待),以及死锁的预防和避免方法。内存管理也是重点,虚拟内存、分页分段、页面置换算法(LRU、FIFO、Clock),这些都是选择题的高频素材。另外,进程间的通信方式(管道、消息队列、共享内存、信号量)也是常客,建议整理成表格对比记忆。
数据库同样是选择题的重点,尤其是索引和事务。索引这块,B+树为什么适合作为索引结构、聚簇索引和非聚簇索引的区别、最左前缀原则、索引失效的几种常见情况(比如对索引列使用函数、隐式类型转换),考察得非常多。事务这块,ACID四个特性要能说出来,隔离级别(读未提交、读已提交、可重复读、串行化)以及它们各自解决的并发问题(脏读、不可重复读、幻读),几乎每年都考。
2.3 数据库与语言细节:很多时候是送分题也是送命题
语言方面的考察,主要取决于你报名时选的岗位方向。Java岗会考JVM的内存区域划分、垃圾回收算法(可达性分析、G1和CMS的区别)、HashMap的底层原理(JDK1.8之后为什么引入红黑树),以及并发编程里的synchronized和volatile关键字。C++岗则会考内存管理(堆栈区别)、指针与引用的区别、虚函数和多态的实现原理。
在这里我想特别提一句,千万不要觉得语言题简单就轻视它。这些题往往是看起来都会,但一做就错。举个例子,关于HashMap,很多人都知道它底层是数组加链表加红黑树,但问到"在什么条件下链表会转红黑树",答案不是笼统的"长度大于等于8",而是要加上"并且数组长度大于等于64"。这种细节就是出题人用来区分"背过八股"和"真正理解"的地方。
Python岗位的话,GIL锁是必考的,还有列表和元组的区别、深拷贝和浅拷贝的区别、装饰器的实现原理。我在准备时重点看了GIL对多线程并发的影响——就算你创建了多个线程,在CPU密集型任务上也无法利用多核优势,这也是为什么Python程序员要转向多进程或异步IO的原因。
心得:考前把网络、操作系统、数据库三块的笔记过一遍,重点记忆各种"条件"和"场景"——什么情况下A会发生、什么情况下B会失效。这类题目就像单词填空,记住了就能得分,记不住再聪明也白搭。
3. 编程题实战:从读题到AC的完整思路
3.1 拿到题目后前10分钟不要写代码
这是我最想强调的一点。很多同学一看到题目有思路,立刻就扑上去写代码,结果写到一半发现边界条件没考虑周全,回头改来改去,浪费时间不说,心态也容易崩。
正确做法是,拿到题目后先花5到10分钟做三件事:第一,把题目重新用自己的话复述一遍,确保没有理解偏差;第二,把题目给出的示例输入输出走一遍流程,确认自己理解的计算逻辑和题目描述一致;第三,盯着数据范围看一会儿,这是最容易忽视但极其重要的一步。
为什么数据范围重要?因为它直接决定了你该用什么算法。如果n小于等于100,你可以放心写O(n^3)的暴力解法;如果n小于等于10^5,你要考虑O(n log n)的算法;如果n小于等于10^7,那基本就是O(n)的线性解法,甚至要考虑空间是否足够。我见过太多人在这上面翻车:明明数据范围是10^9,他还用双层循环,结果是必然超时。读题阶段就把复杂度定好,后面写代码的时候才不会走弯路。
3.2 高频算法套路的解题框架
根据我这几年刷题和参加笔试的经验,以下几个算法套路在携程这类互联网大厂的笔试里出镜率极高,建议你把这些框架练熟。
DFS和BFS,处理图论和搜索问题的万能工具。DFS注意递归终止条件和状态恢复(回溯),BFS注意使用队列记录层数。如果是求最短路径、最少步数,优先想BFS;如果是求所有路径、所有组合,优先想DFS+回溯。框架就几行代码,但关键是知道什么场景下该套哪个。
双指针,处理有序数组和链表问题的神器。快慢指针可以找到链表环的入口,左右指针可以在有序数组里二分查找或者做两数之和。以"两数之和"为例,如果数组是有序的,用左右指针从两端往中间走,时间复杂度是O(n),比暴力解法优化了整整一个数量级。携程这批笔试的压轴题,核心就是双指针加排序。
前缀和和差分数组,处理区间问题的利器。当题目要求频繁计算某个区间的和或差时,用前缀和把O(n)的查询降到O(1)。差分数组适合处理多次区间加减的问题,比如"给区间[l, r]中的所有元素加一个值",用差分数组可以做到O(1)的更新。
动态规划的解题框架就四个步骤:定义状态、写出状态转移方程、确定初始化和遍历顺序、必要时做空间优化。这里面最容易出错的是遍历顺序。比如背包问题,0-1背包要从后往前遍历容量,完全背包要从前往后遍历容量,顺序搞反了,结果就是错的。如果你对动态规划还不够熟练,我建议你把常见的DP题型分类整理,比如背包问题、最长递增子序列、编辑距离、打家劫舍系列,每个题型至少做三道题,彻底吃透。
3.3 时间分配与调试策略
编程题的时间分配,我个人的习惯是:第一题控制在10到15分钟,第二题控制在30分钟左右,第三题如果40分钟内没有思路,果断放弃去检查前面的选择题。
为什么建议放弃第三题?因为笔试的通过标准是总分达到分数线,而不是每道题都要AC。有时候第三题拿个部分分(通过部分测试用例)也能给不少分,与其死磕一道压轴题,不如把前面简单题的分数稳稳拿满。这种策略虽然听起来不够热血,但确实是应试环境下最理性的选择。
调试技巧方面,我的建议是:不要在代码里随手加输出语句来调试,而是用眼睛先"跑"一遍代码,排查逻辑错误。实在不行,构造几个边界测试用例来验证,比如数组为空、只有一个元素、所有元素都相等、目标值不存在等情况。系统提交前,先把代码贴回本地IDE编译运行一遍,确认没有语法错误。在线编辑器没有智能提示,也没有编译错误定位,提前在本地跑通能帮你省下很多无谓的提交次数。
4. 常见失分点与避坑清单
4.1 选择题容易踩的坑
从我和身边人的复盘来看,选择题的失分点往往集中在几个"看起来很简单,实际上暗藏陷阱"的知识点上。
第一个坑是TCP的四次挥手状态迁移。很多人分不清主动关闭方在发送最后一个ACK之后会进入什么状态(答案是TIME_WAIT),以及为什么需要等待2MSL。这个知识点在选择题里反复出现,每次都能筛掉一批人。
第二个坑是数据库的最左前缀原则。题目经常会给你一个联合索引(a, b, c),然后问哪些查询可以用到索引。很多人以为只要查询条件里包含a就一定能用到索引,但实际上如果查询条件是"a = 1 AND c = 2",那么只有a能用到索引,c是用不到的,因为跳过了b。类似这种细节,如果你没亲自验证过,很容易踩坑。
第三个坑是操作系统的死锁判定。给你四个资源分配状态,让你判断是否会发生死锁,很多人看到"资源数量大于进程数量"就认为不会死锁,其实死锁判定的核心是看是否存在循环等待链,资源多照样可能死锁。这类题目最好的应对方法就是画资源分配图,一眼就能看清有没有环路。
第四个坑是Java的整型溢出。比如"long a = 100000 * 100000",你以为结果是10000000000,但实际结果是1410065408,因为右边的乘法在int范围内就溢出了。这种题在选择题里出现时,真的会有一大批人做错。解决办法就是看到大数相乘的情况,立刻想到加L后缀,或者用long类型做中间运算。
4.2 编程题容易踩的坑
编程题的坑主要是细节问题,但一个细节就能让你痛失AC。
数组越界是最常见的错误。比如LeetCode风格的题目,你写了一个dp数组,状态转移时要去访问dp[i-1],但i=0时就会越界。解决办法要么是初始化dp数组时多给一个额外空间,要么是在循环条件里加上边界判断。写代码时一旦出现访问数组下标的操作,就要在心里默念"会不会越界"。
int溢出同样要注意。题目如果允许中间结果超过2^31-1,你就应该用long类型来存。比如计算前缀和时,如果数组长度是10^5,每个元素是10^9,前缀和就会超过int范围,这种情况就要用long[]前缀和数组。
输入输出的坑也很关键。笔试系统的输入格式是固定的,比如第一行是测试用例数量,接下来是多个测试用例。你要严格按照题目描述的格式来读取,不要多读一行,也不要少读一行。另外,如果题目要求输出的浮点数保留两位小数,就一定要用String.format("%.2f", value)或者printf来处理,不要自己手动截断,否则会有精度误差。
递归深度过大导致栈溢出也是个容易被忽略的问题。如果递归深度可能超过10000,就要考虑用迭代方式改写,或者用显式栈模拟递归。笔试系统通常对栈内存有限制,递归太深的代码会直接爆栈。
4.3 考试环境与时间管理问题
这是最后也是最实际的一关。在线笔试系统和本地开发环境是有很大差别的,不要想当然。
首先是输入法问题。很多在线编程环境在写代码时如果要输出中文,需要切换输入法,但系统可能会自动切走你的输入法,导致你打出来的代码变成乱七八糟的标点符号。我的建议是,代码里尽量不要写中文注释,当提交环境有问题时,中文标点可能直接编译报错。
其次是浏览器和网络问题。在线笔试系统一般只支持Chrome或Firefox,如果你用其它浏览器打开,系统可能会提示不兼容。网络也要提前确认稳定,我认识一个同学,笔试到一半网络断了,重新登录后代码全丢了,心态直接崩了。提前找个网络稳定的地方,提前测试一下系统登录是基础中的基础。
注意:在线笔试一般会开启监控,一旦切出浏览器页面就会记录,频繁切出可能会被判定作弊。所以不要指望中途去搜索引擎查资料,考场纪律还是很严格的,备考阶段把该记的都记牢,上考场就靠真本事。
5. 备考节奏与实战建议
5.1 笔试前一个月怎么安排
如果你距离笔试还有一个月左右的时间,我建议你按"刷题为主、背诵为辅、模拟为辅"的节奏来准备。
第一周到第二周,集中刷数据结构和算法题。按专题刷,而不是按随机题号刷。比如周一刷数组和链表、周二刷栈和队列、周三刷二叉树和递归、周四刷动态规划、周五刷贪心和回溯。每个专题刷10到20道经典题,重点看题目背后的解题思路,而不是题量。刷题时养成好习惯:每道题先自己想思路,卡了15分钟再看题解,看懂了之后一定要自己动手写一遍,然后思考有没有可以优化的地方。
第三周开始,穿插背诵计算机基础和语言特性。把网络、操作系统、数据库三块的重点内容整理成笔记,每天早晚各花30分钟背诵。Java或C++的语言细节和JVM、并发相关的内容,同样整理成FAQ的形式。另外,每天做一套选择题模拟卷,不限时,但要求正确率在80%以上。
第四周,进入冲刺阶段。每天做一套完整的模拟笔试,严格卡时间,题目可以从牛客网、LeetCode、以及各大厂历年的真题库中组合。重点锻炼两个能力:一是时间分配能力,知道什么时候该放弃难题;二是心理抗压能力,模拟考试时遇到不会的题,深呼吸、跳过去、继续做,不要在一道题上卡太久。
5.2 笔试当天的注意事项
笔试当天,提前半小时进入系统,先测试一下代码编辑器能不能正常使用,写一段简单的"Hello World"看看编译运行是否顺畅,顺便熟悉一下代码提交的按钮位置。
正式开考后,我的答题顺序是:先快速扫一遍所有题目,选择题一眼就能确定答案的,直接选;拿不准的,先标记跳过,不要在一道选择题上浪费超过2分钟。编程题部分,优先做最有把握的那一道,确保AC一道题保底,然后再去啃硬骨头。
整个过程中要保持冷静。笔试考的不仅是知识储备,更是你在高压环境下的应变能力。遇到不会的题太正常了,关键是不要让它影响你的心态。你要知道,你面前的不只是一场考试,更是一次经验和试错的机会——发挥得好就直接进入面试,发挥不好的话,这次复盘总结的经验,就是你下一次冲刺最大的底气。
备考资料方面,力扣的"热题Hot 100"和"剑指Offer"系列值得反复刷,牛客网上的大厂笔试真题库也很有参考价值。至于要不要买网课,我觉得因人而异,如果你自学能力强,完全可以通过刷题加总结来搞定;如果你需要有人带着梳理知识点,那可以选一套针对校招笔试的系统课程。最忌讳的就是只囤课不刷题——手才是你的核心竞争力,眼睛和耳朵都只是辅助。