刚参加完2023年携程春招技术通用岗第二批笔试,趁记忆还热乎,赶紧把题目类型、考点分布、做题节奏这些整理一遍。这批笔试整体给我的感觉是:不像某些大厂上来就搞 hard 级算法题压场,携程更看重基础扎实度、工程思维和快速编码能力,但并不意味着简单,选择题的覆盖面相当广,稍有不注意就容易翻车。
这篇内容主要面向准备投携程技术岗(后端、客户端、测试开发等通用技术方向)春招/暑期实习的同学,也适合所有在准备互联网大厂笔试时想系统梳理知识点的人。我会把整场笔试从试卷结构、选择题考点、编程题思路、到时间分配策略尽量完整地复盘一遍,结尾再附上一些考场上踩过的坑和备考建议,建议收藏后对着知识点清单自检。
1. 笔试整体结构与考察底层逻辑
1.1 试卷构成与考试环境
先说最直观的。第二批笔试安排在线上进行,用的牛客网系统,双机位监控,手机要放在侧后方。整体时长 90 分钟,题量分布大致是:单选题 20 道左右 + 不定项选择题 5 道左右 + 3 道编程题。
这里有个细节需要提醒:牛客网的在线编程环境默认支持多种语言,我选的 Java,但你要注意携程的笔试系统里,Java 版本并不是特别新,大概是 Java 8 到 11 之间的环境,所以像 records、switch 表达式这种新语法最好别用,万一编译环境不支持,明明思路对了却编译不过,非常冤枉。建议平时写代码就按 Java 8 的习惯来,稳一点。
另外,编程题部分可以自定义输入输出,每道题都有“本地调试”和“保存并提交”两个按钮。每道题的运行时间是分开计时的,不存在“整场考试计时”和“单题计时”叠加的问题,这点比一些银行类笔试要友好。但你切出页面去百度查资料的话,系统会记录切屏次数,超过一定次数可能被判作弊,这个后面避坑清单里我会单独讲。
1.2 从题型设计反推筛选逻辑
很多同学备考时只盯着“考什么”,但我觉得先想清楚“为什么这样考”更重要。携程技术岗笔试的题型设计,其实非常典型地反映了大厂校招筛选的底层逻辑——他们不是要招一个“算法竞赛选手”,而是要招一个“能干活、基础不差、出了问题能自己排查”的准工程师。
- 选择题覆盖面广,对应的是“计算机基础是否扎实”。网络、操作系统、数据库这些课,工作中未必天天直接用到,但遇到线上问题、性能调优时,全凭这些底层知识兜底。
- 不定项选择题,对应的是“对知识掌握的精确度”。单选的排除法在不定项里不好使,你必须真的知道哪个选项对、哪个选项错、为什么错,多选少选都不得分。
- 编程题题量不多但每道都有区分度,对应的是“在有限时间内把思路落地成代码”的能力。毕竟面试时让你手写代码,给的也是这种题。
想明白这层逻辑,就能理解为什么我建议把复习重点放在“基础广度”而不是“算法深度”上。如果你还剩一周时间,与其死磕某道难题,不如把数据结构、计算机网络、操作系统里的常考概念全部过一遍。
2. 选择题模块:核心考点详细拆解
2.1 Java 语言与 JVM 高频易错点
携程作为典型的 Java 技术栈大厂,选择题里 Java 相关比例相当高。我这场考试里,Java 基础大约占了选择题的 30%,题型分布大概是:Java 语法细节 3-4 道、JVM 2-3 道、并发编程 2 道、Spring 框架 2 道。
先说 Java 语法细节,这里有个非常经典的坑——String、StringBuilder、StringBuffer 的区别,考的是“谁线程安全、谁效率高”,这题我见过无数次了,但这次换了个考法,不直接问区别,而是给了一段字符串拼接的代码,问创建了多少个对象。这种题就是典型的“看着简单,错起来不自知”。关键点是字符串常量池缓存、new String 一定创建新对象、字符串变量拼接底层是 StringBuilder.append()。复习时建议把常量池、堆、栈这三块内存区域的分配理清楚。
JVM 部分考了一道老生常谈的题:类加载过程中,静态代码块、成员变量初始化、构造方法的执行顺序。这题本身不难,但配合继承、静态变量、实例变量的情况,容易绕进去。做题时记住口诀:父类静态 → 子类静态 → 父类成员变量 → 父类构造 → 子类成员变量 → 子类构造。
还有一个高频考点是垃圾回收。一般会问“哪些对象可以作为 GC Roots”,这个我后面在避坑清单里会详细展开,因为这是面试里也常被追问的点。
并发编程方面,这次考了 synchronized 和 ReentrantLock 的区别,以及 volatile 的可见性。这类题用排除法也能做对,但要注意:synchronized 是 JVM 层面的锁,ReentrantLock 是 JDK API 层面的锁,前者不需要手动释放,后者必须在 finally 里 unlock。这在笔试里不算难点,但在面试环节被深挖的概率很高,建议理解透。
2.2 数据结构与算法基础:白给的分不能丢
数据结构部分的选择题一般不难,但也最容易因为粗心丢分。二叉树的遍历考了一道:已知前序遍历和中序遍历,求后序遍历。这种题的核心思路是:前序第一个节点就是根节点,然后到中序里找根节点的位置,左边是左子树,右边是右子树,递归即可。笔试时没时间写代码画图,推荐直接用“栈模拟”的心算方法,熟练后十秒内能出答案。
另一个高频考点是排序算法的时间复杂度和稳定性。我这次遇到的是:下列哪种排序算法在最坏情况下时间复杂度为 O(n²) 且不稳定?选项里有快排、归并、堆排、插入排序。这里要特别注意,快排平均 O(nlogn)、最坏 O(n²)、不稳定;归并始终 O(nlogn)、稳定;堆排 O(nlogn)、不稳定;插入排序 O(n²)、稳定。建议把常见排序的“最坏/平均/最好时间复杂度 + 空间复杂度 + 稳定性”整理成一张表,考前背熟。
哈希表是常客。这次考了“哈希冲突的解决方法”的不定项选择,选项有开放定址法、链地址法、再哈希法、建立一个公共溢出区。这四个都是对的,属于送分题。但换一种考法就要注意了:“Java HashMap 中解决冲突用的是什么方法?”答案是链地址法,但 JDK 1.8 之后链表长度超过 8 且数组长度大于等于 64 时会转成红黑树,这个细节也经常被考到。
2.3 计算机网络、操作系统与数据库覆盖面分析
这三块合计大约占选择题的 25%-30%,题量不多,但出现的点非常集中。
计算机网络里,TCP 三次握手和四次挥手是绝对的高频,一定要把状态变迁背熟。这次考的是 TIME_WAIT 状态:主动关闭连接的一方,在发送最后一次 ACK 后进入 TIME_WAIT 状态,持续 2MSL,为什么是 2MSL?因为要保证最后一次 ACK 能到达对方,如果丢了可以让对方重发 FIN,同时让本连接产生的所有报文段从网络中消失。这几个点都理解了,答这种题就不会错。
HTTP 状态码也要注意。202、302、400、401、403、404、500、502、503 这些常见状态码的含义必须脱口而出。携程这种业务复杂度高的公司,很爱考 401 和 403 的区别:401 是未认证(没登录),403 是已认证但无权限。这俩经常被混在一起做迷惑项。
操作系统部分主要考进程和线程、死锁、内存管理。这次考了死锁产生的四个必要条件(互斥、占有并等待、非抢占、循环等待),题目是“破坏循环等待条件可以预防死锁”,对应的是资源有序分配法。这类题属于概念记忆题,得分率应该高,丢了很可惜。
数据库方面必考索引和事务隔离级别。索引这边最典型的题是:给一条 SQL,问命中索引的情况。需要重点掌握联合索引的最左前缀匹配原则。事务隔离级别这道题,要把读未提交、读已提交、可重复读、串行化分别解决什么问题、存在什么问题(脏读、不可重复读、幻读)全部理清楚。MySQL 默认隔离级别是可重复读,InnoDB 引擎通过 MVCC + 间隙锁解决幻读,这些知识点在面试中同样重要。
3. 编程题模块:从破题思路到 AC 实战
3.1 第一题:字符串模拟类,热身但暗藏细节
编程题第一题通常是“热身难度”,但绝对不是“白给难度”。这场的题目给的是一个字符串处理场景:给定一个由数字和字母组成的字符串,要求将其中连续的数字子串识别出来,按原顺序拼接后输出,如果没有任何数字子串,输出空行。
这题核心考点是“边界处理”,千万不要只在脑子里想思路,而是得在草稿纸上把边界情况列出来:
- 字符串为空时怎么处理?
- 字符串以数字开头和以字母开头时,切分逻辑是否一致?
- 连续数字子串之间可能有多个字母分隔符,是否需要去重?
- 输出格式:每个数字子串之间用逗号分隔还是空格分隔?
我给的参考解法是双指针滑窗,一次遍历搞定。维护一个 start 指针标记数字子串起点,i 指针向后扫描,遇到字母时判断 i 是否大于 start,是则说明找到了一个数字子串,截取加入结果集。
对于笔试场景,这道题花了大概 10 分钟。做完后我强烈建议你“手动构造几个特殊用例”提交验证,不要直接交卷。比如输入字符串是空串、输入是“abc”、输入是“123abc456”、输入是“abc123def456ghi”,这四个用例覆盖了大多数边界情况,能保证第一题稳拿分。
3.2 第二题:贪心 + 区间问题,考验排序思维
第二题是一道区间调度类问题。核心场景是:给定若干条业务请求,每条请求有开始时间和结束时间,同一个人在同一时刻只能处理一个请求,问最多能处理多少条请求。
这道题非常经典,技术圈一般叫“会议室问题 II”或“无重叠区间”变体。如果之前刷过 LeetCode 435 或 252,看到题的第一反应就应该是贪心。贪心策略是:按结束时间从小到大排序,然后依次选择“开始时间不小于上一个选中区间的结束时间”的区间。
我当时用的思路是这样的:
- 用二维数组或者 List<int[]> 存所有区间;
- 按区间右端点升序排序,如果右端点相同,按左端点升序;
- 遍历排序后的区间,维护一个变量 lastEnd 记录上一个选中区间的结束时间;
- 当前区间左端点 >= lastEnd 时,选中,答案加一,更新 lastEnd。
这题整体时间控制在 15 分钟左右,核心难点不是贪心本身,而是能不能在紧张状态下快速判断出“该用什么算法”。建议备考时多做几道区间类题目,形成条件反射——看到区间调度,先想排序,再想贪心。
3.3 第三题:动态规划,区分度主要在状态定义
第三题是一道动态规划,也是三题中唯一一道有区分度的题目。场景大概是这样:给定一个整型数组,每个元素代表一天结束后股票的收益变化值,你可以选择在某一天买入、某一天卖出,也可以选择不操作,问最大收益是多少。
千万不要被“股票”这两个字带偏,这题本质就是“最大子数组和”的变体。LeetCode 121 的经典版本是只允许买卖一次,最直观的解法是维护“到当前天为止的最低价格”和“到当前天为止的最大收益”,一次遍历搞定。但这次笔试的数据范围更大,而且可能支持多次交易,所以我一开始先扫了一下数据规模,确认是单次交易后就直接用 O(n) 的贪心写了。
不过要注意,携程笔试的第三题经常会在经典题基础上加一点点变体。比如:必须至少完成一次买入卖出,或者数组中存在负数。这些约束变化会导致初始值设置不同。我建议遇到动规题时,先写状态转移方程,再初始化,最后再想代码实现。顺序反了容易乱。
我用的是这组核心逻辑:
int minPrice = Integer.MAX_VALUE; int maxProfit = 0; for (int price : prices) { if (price < minPrice) { minPrice = price; } else if (price - minPrice > maxProfit) { maxProfit = price - minPrice; } }虽然是经典题,但笔试中能一次 AC 的人并没有想象中多,因为很多人忽略了边界条件:数组长度小于 2 时,收益一定是 0,而不是“买入卖出的差价”,因为根本没法交易。
4. 时间分配与实战做题策略
4.1 90 分钟怎么切分最合理
合理的分配方式可以拆成“前 45 分钟选择题 + 后 40 分钟编程题 + 最后 5 分钟检查”。注意,我建议选择题不要超过 50 分钟。别小看这点:20 道单选 + 5 道多选,平均每题不到 2 分钟,其中有些 Java 和并发题需要认真读代码,时间其实很紧。
编程题一共 90 分钟,但如果你前面选择题拖到 55 分钟以上,后面三题就只剩 35 分钟,大概率第三题只能写个思路框架。所以,我的建议是:
- 拿到试卷先别急着做,花 30 秒通读所有题目,给每道题一个“预计耗时”的心理预期;
- 选择题遇到完全没思路的,先标个记号,果断跳过,不要恋战;
- 选择题一轮做完后,如果有剩余时间,再回头啃跳过的题;
- 编程题按“先易后难”顺序做,不要按题目顺序。
4.2 选择题的“性价比”做题法
这里分享一个我对“性价比”的理解:同样的 2 分,花 30 秒能拿到的和花 5 分钟才能猜到的,前者性价比高得多。所以选择题部分的战略是——把简单题全部快速拿分,把中等题尽量拿分,把难题放到编程题做完之后再回来看。
怎么判断一道题是不是“难题”?我的经验是:如果读完题干和选项后 10 秒内没有任何思路,直接跳到下一题。这种题通常涉及冷门框架、不常见的 API、复杂的多态继承组合,想靠临场推理推出来,概率很低。
不过,不定项选择是个例外。因为不定项少选不得分,所以如果不确定某个选项是否正确,就不要冒险选它。宁可少选一个,不要多选一个错的。这是做不定项选择的一个基本操作,但真到了考场上,有些同学会因为“蒙一个说不定能对”的心态,把不确定的选项也勾上,结果整题分数全丢。
4.3 编程题的容错与“保一争二望三”策略
编程题三题,常见的时间分配是 10 分钟 + 15 分钟 + 20 分钟,视题目难度调整。核心策略是:第一题必须 AC,第二题尽量 AC,第三题保底写出主要逻辑。
第一题一般是字符串、数组、栈队列的基础题,只要认真审题、边界处理到位,AC 问题不大。第二题会考到排序、二分、贪心、前缀和、双指针中的一个,属于“刷过题就会、没刷过就卡壳”的题型。第三题通常是动态规划或复杂模拟,是第一轮就能筛掉一批人的分水岭。
如果第三题确实没思路,我的建议是:不要空着,把暴力解写上。哪怕超时,也能拿到一部分用例分。很多在线笔试平台是“按通过的用例比例给分”,暴力解能通过 20%-40% 的用例,好过一分不得。注意多拿部分分,不是丢人的事,是策略。
5. 考前一周的高效准备思路
5.1 按“岗位通用”要求建立知识清单
技术通用岗笔试的名头很直观——它不区分 Java、C++、前端,所有技术方向用同一套题。所以不会考太深的技术栈细节,但计算机基础、逻辑思维、算法基本功会被反复考察。我建议考前一周按下面的清单过一遍,不要求每一个细节都抠死,但至少看到题目时能快速反应出考点:
| 模块 | 核心考点 | 优先级 |
|---|---|---|
| Java 基础 | 集合类、String、异常、泛型、反射 | 高 |
| JVM | 内存区域、类加载、GC、垃圾回收器 | 高 |
| 并发 | 线程池、锁、volatile、synchronized、CAS | 中高 |
| 数据结构 | 树、图、链表、栈、队列、哈希表 | 高 |
| 算法 | 排序、二分、贪心、动态规划、递归 | 高 |
| 计算机网络 | TCP/UDP、HTTP、DNS、网络模型 | 中高 |
| 操作系统 | 进程线程、死锁、虚拟内存、页面置换 | 中 |
| 数据库 | 索引、事务隔离级别、SQL 语法 | 中高 |
| Spring | IOC、AOP、Bean 生命周期 | 中低 |
表格里的“优先级”是我个人的判断——Java 基础和数据结构算法一定是最重要的,因为占比最高;Spring 虽然考得不多,但在国内互联网公司笔试里几乎每次都有,不能完全放弃。
5.2 刷题重点:LeetCode 高频题型的套路化总结
关于刷题,我不建议考前一周再去开新题,而是应该做“套路化总结”。LeetCode 上有太多题,但笔试遇到的题,说到底就那几个模式:数组双指针、二叉树遍历、动态规划状态机、区间问题、字符串处理。
我把这几个模式的具体题目按优先级列一下,你可以在 LeetCode 上直接搜编号刷:
- 双指针:LeetCode 11(盛最多水的容器)、15(三数之和)、42(接雨水,hard 可跳过,但思路要懂);
- 区间:LeetCode 56(合并区间)、252(会议室)、435(无重叠区间);
- 动态规划:LeetCode 121(买卖股票)、198(打家劫舍)、322(零钱兑换);
- 二叉树:LeetCode 102(层序遍历)、236(最近公共祖先);
- 字符串:LeetCode 3(无重复字符的最长子串)、8(字符串转换整数)、151(反转字符串中的单词)。
这里注意,每道题做完之后,不要急着刷下一道,花 10 分钟做复盘:这道题属于什么类型?核心解法是什么?如果换一种数据范围,解法需要怎么变?——这么做能让你在真实笔试中举一反三,而不是靠背题。
5.3 从环境到心态:容易被忽视的考前细节
最后,再说几个考前容易被忽视的细节。
第一,提前调试摄像头和浏览器。牛客系统对浏览器版本有要求,Chrome 是最稳妥的,考试前一定要先打开模拟测试环境,走一遍摄像头检测、麦克风检测、屏幕录制授权的全流程。每年都有同学因为浏览器插件问题,在正式考试时才发现自己进不了系统,心态直接崩掉。
第二,找一个网络稳定、安静独立的空间。尽量用有线网络连接电脑,或者确保 Wi-Fi 信号满格。笔试过程中断网超过一定时间系统会自动交卷,这个设定特别残酷,没有申诉机会。
第三,身份证件放在手边。开考前需要拍照验证身份,如果手边没证件,会延误进入考试的时间。
第四,心态上不要被第三题吓住。考场上大概率会遇到没见过的题,此时记住一句话:你不是要考满分,你只需要比同一批竞争者多拿几分。把会的题全部做对,拿到的分已经足够进面了。
6. 常见问题与避坑经验整理
6.1 笔试系统操作层面的坑
先讲系统层面最容易踩的几个坑,这些遇到一个就足够影响成绩:
- 切屏次数过多被判违规。考试过程中系统会监测页面焦点变化,只要切出考试页面,就记录一次。很多同学不知道这点,做题时想打开本地 IDE 调试代码,切屏两次后收到警告,到第三次可能直接被强制交卷。应对方式是:在线编程题的本地调试功能才是允许的通道,不要在测试过程中尝试打开浏览器新标签页。
- 浏览器弹窗拦截。牛客网有时会弹出代码编辑器的新窗口,如果浏览器默认拦截了弹窗,代码编辑器会显示空白,但计时器还在跑。建议提前把牛客网加入允许弹窗的站点列表。
- 未保存答案就切到下一题。牛客网一般会自动保存答案,但偶尔有网络波动,自动保存会失败。我的习惯是每做完一题,点击“下一题”前,刷新一下页面看答案是否还在。这个操作不到 5 秒,但能避免大问题。
6.2 知识层面的做题陷阱
知识层面的避坑,主要集中在选择题的迷惑项设置上。我整理了几个高频命题套路:
一是“范围扩大/缩小”陷阱。比如问“以下哪些是进程间通信方式”,选项里混入“线程间共享内存”,这属于概念的层次混淆。线程间通信本质是共享进程的内存空间,不涉及内核切换,这不是进程间通信。
二是“概念混搭”陷阱。比如“TCP 是可靠传输协议,因此不存在丢包”,前半句对,后半句错。TCP 只能保证“尽力可靠”,如果网络断开、对端崩溃,TCP 也无法保证数据一定送达。
三是“多关键字”陷阱。题目问“以下哪些操作会导致线程不安全”,选项里列出 Vector、Hashtable、StringBuilder、SimpleDateFormat。前两个是线程安全的,但很多人一看到 ArrayList 线程不安全,就惯性思维以为所有集合都不安全,忽略了一部分集合类本身就是线程安全的。
四是“特性张冠李戴”陷阱。比如把 HashMap 的特性放到 TreeMap 上描述,或者把 ArrayList 的扩容机制套到 LinkedList 上。这种题要求你精确记忆每种数据结构的关键特性,不能只记个大概。
6.3 关于备考与面试衔接的一些实话
有些同学把笔试和面试割裂开复习,笔试前刷题,面试前背八股,这么做低效。携程的面试环节一定会深挖笔试里出现的知识点,尤其是编程题,面试官可能会问:“你第三题用的贪心思路,能证明一下为什么贪心是最优的吗?”这是面试官很爱问的一个追问题,如果面试时能答上来,其实是一个很加分的展示点。
所以笔试结束后,建议立刻趁记忆清晰,把自己写的代码和解题思路整理成文档,包括:题目理解、解题思路、时间空间复杂度分析、边界条件处理、是否可以优化。这个文档在 3-7 天后的面试复习中非常有用。即使这道题面试没再问,整理的过程本身就是高效的复盘。
另外,笔试中遇到的不确定选项,也建议考后立即查证、记录。我当时有一道“GC Roots 包括哪些对象”的不定项选择题没把握,考后我专门查了资料,把结论整理成了笔记:虚拟机栈中的引用对象、静态属性引用的对象、常量引用的对象、JNI 引用的对象、活跃线程。这种题如果能在面试前彻底搞懂,价值比背十道新题还高。
写在最后:一个亲测有效的复盘方法
我考完这批笔试后,没有急着准备下一家,而是先花了一个晚上做了一个详细的复盘表,把每一道选择题的考点、当时的犹豫点、正确答案、对应复习资料都列了出来。做完之后我发现,自己真正丢分的地方集中在 1-2 个模块的知识盲区,而不是“不会做题”。这种针对性的薄弱点排查,比闷头刷题有效得多。
这个复盘方法你也可以直接用:考后 24 小时内,趁记忆最深的时候,把所有题目录成表格,标注不确定的题、瞎蒙的题、完全没思路的题,再逐一对应到知识点。用不了一晚上,但能让你接下来的面试准备方向清晰很多。笔试只是第一关,把每一次笔试都变成一份“个人知识漏洞地图”,你的面试准备才会越来越有针对性。