
2019年那会儿互联网校招还处在“金九银十”的黄金期携程作为OTA老大哥笔试难度在行业内属于中上水平尤其是研发岗筛人挺狠的。当时我正好完整走了一遍携程秋招流程从专业笔试到后面的技术面一路踩了不少坑。趁着这几天整理旧电脑里的面试笔记翻出当年的笔试题复盘了一遍发现很多考察点到现在依然是各大厂笔试的常客。这篇就把当年携程研发方向专业笔试的整个情况拆开揉碎讲清楚包括题型分布、核心考点、一些典型题目的解题思路以及我当时是怎么准备和复盘。不管你是正在准备校招的应届生还是打算跳槽去OTA行业、想了解大厂研发笔试套路的在职开发这篇内容都能给你一个比较完整的参考坐标系。尤其是数据结构与算法、Java基础、数据库、网络这些核心科目我会把当年的真题和附近几年的相似考点结合起来讲告诉你哪些是真正值得投入时间的。1. 整体笔试结构与方向拆解1.1 研发方向笔试的科目构成携程2019届秋招专业笔试研发方向用的是牛客网平台线上笔试全程摄像头监控加屏幕录制。整体题量和时间搭配是这样的笔试时长90分钟题型构成单选题约20道、多选题约5道、编程题2道分值分布选择题每题2分左右编程题每题20分总分100分上下浮动考察范围数据结构与算法、Java基础部分岗位涉及C、计算机网络、数据库、操作系统、逻辑思维题当时所有人拿到的是一套综合卷不会像社招那样分Java岗卷、C岗卷而是不管你投的是Java研发还是前端研发只要属于技术研发大类笔试都是同一套。这意味着题目难度会取一个中间值不会太偏门但覆盖面很广每一科都可能冒出来几道题。时间上一定要提前算好账。90分钟做25道选择题加2道编程题平均每道选择题只有1分多钟加上读题和思考时间其实相当紧张。编程题如果认真写一道题20分钟很正常两道题就得留出40分钟。所以真正留给选择题的时间也就50分钟上下遇到不会的必须果断跳过不然编程题根本没时间写。1.2 不同岗位方向的侧重差异虽然是一套综合卷但携程在研发方向下其实细分了好几个岗位包括Java开发、前端开发、客户端开发、大数据开发、算法工程师等。这里有个很有意思的点Java开发、大数据开发选择题偏Java语法、JVM、集合源码、Spring框架编程题偏算法与数据结构前端开发选择题偏JavaScript、浏览器原理、HTTP协议编程题依然偏算法算法工程师选择题偏机器学习基础、概率统计编程题不仅有算法还可能有简单的数学推导客户端开发Android/iOS选择题偏Java或Objective-C、操作系统、网络我当时投的是Java研发。下面我讲的细节主要以Java研发方向看的题目为主但算法和网络部分对其他方向同样适用。笔试最大的坑点在于你不会知道具体岗位对应哪套题直到你打开试卷的那一刻。所以备考时不能只钻自己岗位的技术栈数据结构和算法是绝对的重中之重所有方向的编程题都跑不掉。我当时就是前期花了大把时间刷算法虽然选择题里Java相关的题目没有全部答对但编程题两道都AC了最后顺利进入了面试环节足以说明算法题在总分里的权重有多大。2. 核心题型与考点深度分析2.1 数据结构与算法笔试的得分基本盘无论哪个大厂的研发笔试数据结构与算法永远是重头戏携程也不例外。选择题部分算法与数据结构相关题目大概能占到30%到40%编程题干脆全部是算法题所以这一块直接决定了你能不能过笔试线。当年选择题里考察的知识点我整理了一下基本都是这些老面孔栈和队列的特性及应用场景比如用栈实现队列、用队列实现栈的经典操作二叉树的遍历方式前序、中序、后序、层序常考的是根据中序另一种遍历推树的结构二叉搜索树和堆的插入、删除、调整过程考时间复杂度哈希表的冲突解决方法开放定址法、链地址法负载因子对性能的影响排序算法的稳定性、时间复杂度和空间复杂度对比我记得特别清楚的一道题给定一棵二叉树的前序遍历序列和后序遍历序列问能不能唯一确定这棵二叉树。答案是不能。因为前序后序无法确定左右子树的分界点必须要有中序遍历参与才行。这个考点反复出现在各大厂笔试中是最容易拿分也最容易失分的基础题。再举一个当时让我卡了半天的选择题问的是“快速排序在什么情况下时间复杂度退化到O(n²)”。选项里有一个“每次划分都选到最大或最小元素作为基准值”这就是正确答案。当时我选成了“数据已经完全有序”后来复盘才发现不完全对——如果选中间值就算数据有序也不会退化。所以学算法不能只背结论要把原理吃透。编程题方面2019届携程的两道题一道是字符串处理类的中等难度题一道是动态规划类的常规题。字符串那道题具体是给一个只包含小写字母的字符串要求找出最长不含重复字符的子串长度这是LeetCode上的原题滑动窗口解法。动态规划那道题是背包问题的变种给一组物品的重量和价值背包容量有限求最大价值可以用一维dp数组优化空间。两道题都不算变态难但对编码实现能力有要求。尤其是滑动窗口那道题如果不熟悉双指针的写法很容易写出O(n²)的暴力解法虽然测试数据不大也能过但万一数据加强就会超时。我当时用的HashMap记录字符上次出现的位置一次遍历搞定时间负责度O(n)空间O(n)。2.2 Java基础看似简单但最容易丢分的部分Java基础知识的选择题对科班出身的同学来说应该是最亲切的部分但恰恰是这里最容易阴沟翻船。因为出题人会在一些“看似简单”的地方设置陷阱专门考察你对源码和底层机制理解的深度。携程Java方向的选择题涉及这些典型的Java考点String、StringBuilder、StringBuffer的区别以及String在拼接时的内存变化HashMap的底层实现原理JDK1.7和1.8的差异链表转红黑树的阈值ArrayList和LinkedList的增删改查时间复杂度对比多线程相关synchronized和ReentrantLock的区别volatile关键字的作用JVM内存区域划分堆、栈、方法区各存放什么数据异常体系checked exception和runtime exception的区别有一道印象很深的题String s1 new String(abc)这行代码创建了几个对象答案是如果常量池中之前没有“abc”则创建两个对象一个在堆中一个在常量池中如果常量池中已有则只创建一个。这个题几乎年年出现在Java笔试里但每次做错的人都不少因为大家容易忽略常量池的缓存机制。另外一个高频考点是HashMap在JDK1.8中的put过程。选择题会问当链表长度超过多少时转红黑树答案是8。顺便还会问为什么是8这时候就要知道是根据泊松分布计算的在负载因子0.75的情况下链表长度达到8的概率极低不到千万分之一。这种细节题目平时不读源码纯粹刷题的话很难答对。我当时的策略是Java部分不追求全对但保证基础语法题全对。像HashMap源码这种如果只是应付笔试了解核心机制就行不用把每一行源码都背下来等到面试前再深挖也不迟。2.3 计算机网络无处不在的HTTP与TCP互联网公司的笔试网络题几乎是必考的毕竟做开发离不开网络通信。携程的笔试卷里网络相关的选择题大概占10%左右主要集中在这几个知识点TCP三次握手和四次挥手的过程以及为什么需要三次握手HTTP和HTTPS的区别HTTPS的加密过程TCP和UDP的区别各自适用的场景常见端口号比如HTTP是80HTTPS是443MySQL是3306有一道题是让选择TCP和UDP的特点选项里有“TCP是面向连接的UDP是无连接的”“TCP提供可靠传输UDP不保证可靠传输”“TCP有拥塞控制UDP没有”“UDP传输效率比TCP高”等等几乎全是正确的选不正确的那项反而更难。这种题考察的就是你对基础概念的精确掌握程度模棱两可的人在这个题上会非常纠结。还有一道关于HTTP状态码的题给出了几个状态码让匹配对应的含义。其中有一个是302选项里写成了“永久重定向”其实是“临时重定向”301才是永久重定向。这种细节点如果不留意很容易选错。当时我就差点掉坑里幸好复习的时候专门整理过状态码。不过话说回来网络题考的深度其实有限完全不会像面试那样让你手写TCP报文格式或者详细描述拥塞控制的四个过程。笔试只要能分清概念、记住关键机制就够了。2.4 数据库与操作系统基础概念的拉分项数据库和操作系统在携程笔试里占比不大大概也是各10%左右但这两部分的题目相对固定好好准备是能拿满分的。数据库部分考点主要集中在SQL语句的基本操作尤其是GROUP BY和HAVING的配合使用索引失效的场景比如对索引列使用函数、模糊匹配以%开头等事务的ACID特性隔离级别和脏读、不可重复读、幻读的关系内连接、左连接、右连接的区别这个经常会出SQL题有一道题让我印象深刻一张学生表一张选课表要查询“没有选任何课程的学生”给了四个SQL选项其中正确做法是用LEFT JOIN然后判断选课表的ID为NULL。这个考察的就是SQL外连接的实际运用属于比单纯背概念更高一层的能力。操作系统部分考点主要集中在这几块进程和线程的区别协程的概念死锁的四个必要条件互斥、持有并等待、不可剥夺、循环等待页面置换算法FIFO、LRU、LFU进程间通信方式管道、消息队列、共享内存、信号量、Socket死锁那道题几乎是必考。2019年携程的选择题里就问破坏死锁哪个条件可以预防死锁答案是把“持有并等待”改为“一次性申请所有资源”。这种题不涉及复杂计算但前提是你得把死锁的四个必要条件记得滚瓜烂熟哪怕漏掉一个都可能做错。3. 编程题实战复盘与解题思路3.1 题目一字符串去重与排序的变种2019届携程研发笔试的第一道编程题我记得很清楚是这道给定一个字符串请将字符串中字符按照出现的次数降序排列如果出现次数相同则按照字符的ASCII码升序排列。输出排序后的字符串。这个题目看起来很简单但有几个坑点藏在细节里字符不只是小写字母可能是任意ASCII可见字符包括数字、大写字母、符号所以不能假设只有26个字母需要先统计频率再排序排序规则是双关键字输出的是排序后的完整字符串不是字符列表注意拼接效率我的解法和思路是这样的public static String frequencySort(String s) { // 统计每个字符出现的次数用长度为128的数组即可 int[] freq new int[128]; for (char c : s.toCharArray()) { freq[c]; } // 将字符和频率封装成对象便于排序 ListCharacter chars new ArrayList(); for (int i 0; i 128; i) { if (freq[i] 0) { chars.add((char) i); } } // 双关键字排序先按频率降序再按ASCII升序 chars.sort((a, b) - { if (freq[a] ! freq[b]) { return freq[b] - freq[a]; // 频率降序 } return a - b; // ASCII码升序 }); // 拼接结果 StringBuilder sb new StringBuilder(); for (char c : chars) { for (int i 0; i freq[c]; i) { sb.append(c); } } return sb.toString(); }这道题在牛客网上对应的是LeetCode 451号题的变种。笔试时有几个同学反馈说自己的代码在本地IDE跑得好好的但提交后只能过部分测试用例问题几乎都出在“没有考虑字符范围”或“频率相同时没有按ASCII升序”这两处。复盘后要记住一个关键点数组长度为128还是256看起来只是数字大小的问题但在某些字符编码下会直接导致越界。当时笔试题目没明确说明字符范围最稳妥的做法是先用HashMa pCharacter, Integer统计避免数组下标越界问题。不过用数组的解法性能更好适合在竞赛条件下使用关键是要把边界条件判断清楚。3.2 题目二动态规划经典背包问题变种第二道编程题是背包问题的变种有一个容量为W的背包和n个物品每个物品有两个属性重量w[i]和价值v[i]。每个物品只能选择放或不放求背包能装下的最大总价值。这就是典型的0-1背包问题。解题代码如下public static int knapsack(int W, int[] w, int[] v) { int n w.length; int[] dp new int[W 1]; // 外层循环遍历物品内层循环倒序遍历容量 for (int i 0; i n; i) { for (int j W; j w[i]; j--) { dp[j] Math.max(dp[j], dp[j - w[i]] v[i]); } } return dp[W]; }这里有一个必须讲清楚的细节内层循环为什么必须倒序遍历因为0-1背包要求每个物品只能取一次。如果正序遍历容量dp[j - w[i]]可能已经被当前物品更新过了等于同一个物品被放入了多次这就变成了完全背包问题。倒序遍历可以保证dp[j - w[i]]是上一轮循环的结果即没有放入当前物品时的最优解。这个知识点不仅在笔试中反复出现面试时也经常被追问属于必须100%理解的范畴。当时我用的是一维dp数组优化版本空间复杂度从O(n * W)降到O(W)代码也更简洁。笔试平台用的是牛客网在提交时需要自己处理输入输出用的是Scanner读数据。这里有个小细节如果输入数据量很大Scanner的效率会偏低可以用BufferedReader替代提高读入速度。不过老实说这道题对于刷过LeetCode或者《剑指offer》的同学来说并不难。每年大厂笔试动态规划题大多逃不出背包、爬楼梯、最长公共子序列、最长递增子序列这几种模型把这几类题练到位编程题至少能保底AC一道。3.3 笔试系统里的输入输出陷阱说到牛客网笔试就不得不提输入输出的处理方式。很多在LeetCode上刷题刷习惯了的人一到牛客网就会卡在输入解析上因为牛客网要求自己写完整的main函数不能用LeetCode那种只写核心方法的模式。当时携程笔试有两道编程题输入格式分别是第一题输入是一个字符串直接scanner.nextLine()读取即可。第二题输入格式是10 3 1 2 3 4 5 6第一行是背包容量和物品数量后面每行是一个物品的重量和价值。读取方式是Scanner sc new Scanner(System.in); int W sc.nextInt(); int n sc.nextInt(); int[] w new int[n]; int[] v new int[n]; for (int i 0; i n; i) { w[i] sc.nextInt(); v[i] sc.nextInt(); }这里容易踩的坑是用nextInt()读完后如果下一行想用nextLine()读字符串会因为换行符残留导致读取到空字符串。所以最好统一用next()或者nextInt()不要混用。另一个常见问题是有些笔试平台允许多组测试用例输入需要循环读取直到EOF写成while (sc.hasNext())的形式。携程当时不算变态只有一组输入但其他大厂不一定所以建议备考阶段就把各种输入模式练熟。4. 那些年我在笔试中踩过的坑4.1 时间分配失误选择题占了太多时间第一次参加携程笔试时我的时间分配完全不合理。前面选择题碰到几道不太确定的题我非要死磕甚至拿出草稿纸画图推导结果做完选择题已经用了70分钟只剩20分钟做两道编程题心里慌得不行。第一道编程题倒是很快就写完了但第二道本来能AC的题目因为时间不够只写了一半提交时还没编译通过。那次笔试最终挂在编程题上让我非常懊悔。这个教训在后来的其他大厂笔试中让我彻底改了策略先写编程题再做选择题。因为编程题分值高且只要有思路就能写写对了基本能拿满分选择题做得再快一道也就2分。就算选择题最后来不及做全蒙一个选项还有四分之一的正确率损失可控。当然不同平台的题不能切换牛客网可以做到先跳到最后一道编程题再回过去做选择题这个功能一定要熟练使用。4.2 编程题不检查边界条件编程题丢分最冤的情况不是不会做而是没注意边界条件导致只过部分测试用例。回顾我自己的笔试经历和周围同学反馈这些边界问题是最常见的输入字符串为空或长度为0时代码是否还能正常工作数组长度为0或1时排序、遍历类算法是否越界目标值比数组中所有元素都大或都小时二分查找的返回值是否合理字符串中出现不可见字符或者空格时统计逻辑是否出错比较稳妥的做法是写完核心代码之后用几组极端的例子自测// 测试空字符串 System.out.println(frequencySort()); // 期望输出空字符串 // 测试单字符 System.out.println(frequencySort(a)); // 期望输出 a // 测试所有字符出现次数相同 System.out.println(frequencySort(ababab)); // 期望输出 aaabbb这种自测习惯平时刷题时就要养成不然笔试那种高压环境下更容易忽略。4.3 选择题的“最优答案”陷阱携程笔试的选择题有个特点部分题目是严格单选但个别题目会有“最合适”“不正确”这类语义修饰读题时稍一马虎就容易做反。比如那年有个多选题问“以下哪些属于TCP协议的特点”选项有“可靠传输”“面向连接”“支持广播”“全双工通信”。因为TCP不支持广播所以“支持广播”是不选的但如果你没看清楚题目问的是“哪些属于”可能会做成“哪些不属于”。应对方法只有一个读题时把“正确的”“不正确的”“属于”“不属于”这些关键词圈出来在草稿纸上标记好。这个习惯不仅适用于笔试面试手撕代码时同样重要。5. 备考路线与实用资源推荐5.1 算法刷题的正确姿势如果你想备战下一年的携程秋招或者正在准备其他大厂的研发笔试我建议按这条路线安排算法部分第一步掌握基础数据结构。数组、链表、栈、队列、哈希表、树、图每种结构的实现原理和常见操作复杂度要烂熟于心。这个阶段不需要大量刷题先求理解。第二步分类刷题。按知识点分类刷LeetCode优先覆盖以下高频题型数组与字符串双指针、滑动窗口、前缀和链表反转、合并、找环树遍历、最近公共祖先、路径和动态规划背包、子序列、编辑距离排序与查找快排、归并、二分变种栈与队列单调栈、优先队列刷题数量上不求多但求每道题都弄明白。我当时从暑期开始每天3到5道题坚持了两个月左右到笔试前总计刷了300道左右基本覆盖了常考题型。第三步做真题和模拟题。牛客网上有历年各大厂的笔试真题库考前两周集中做真题限定时间模拟真实笔试。这样做的好处是能让你适应真实笔试的时间压力和输入输出格式。5.2 Java基础的复习重点Java部分的复习建议按照面试高频考点来准备既要会做选择题又要能应付面试追问String类的不可变性以及String s new String(a)创建对象的数量问题HashMap的put和get过程JDK1.8中链表转红黑树的细节JVM运行时内存区域划分堆和栈的区别垃圾回收算法和常见的垃圾收集器多线程基础Thread、Runnable、Callable线程池的创建和使用synchronized和Lock的区别volatile的内存语义类加载过程加载、验证、准备、解析、初始化我复习时用的方法是先看一遍《Java编程思想》和《深入理解Java虚拟机》把知识框架搭起来然后直接刷各大厂的真题选择题。真题里反复出现的知识点就是重点再回到书里看对应的深挖内容效率非常高。5.3 数据库与网络的快速突击数据库和网络在笔试中占比虽然不大但这部分是最好拿分的。如果你把复习时间看做一种投资那这两科的性价比非常高因为考点极其固定基本不会超纲。数据库重点准备SQL连接查询INNER JOIN、LEFT JOIN、RIGHT JOINGROUP BY与HAVING的配合索引失效的常见场景事务隔离级别与并发异常网络重点准备TCP三次握手、四次挥手HTTP状态码含义HTTP与HTTPS的加密过程TCP与UDP的对比与适用场景我当时是花了一个周末集中背完这两块的考点然后刷了几十道真题选择笔试时基本没有失分。6. 常见问题与复盘建议6.1 笔试结束后如何高效复盘笔试结束后千万别对完答案就扔一边。正确做法是趁热打铁把每一道题都过一遍做对的题快速回忆一下考点确认自己是真的掌握而不是蒙对的做错的题分析错因是知识点缺失、读题失误还是时间不够编程题如果没AC找到正确解法和别人写的优秀代码对比自己的思路差距我当时用一个Excel表格记录每次笔试的战报包含日期、投递公司、题目类型、正确率、错因分析。这样做的价值是你能直观看到自己哪类知识点最薄弱后续复习就有的放矢而不是每次从头到尾无差别复习。6.2 平时时间不够怎么办如果你是现在才开始准备离笔试只有两三周那就要懂得取舍。优先级排序应该是第一优先级数据结构与算法。编程题是最大的分值来源没有捷径可走。至少要把字符串、数组、链表、树、动态规划这五类高频题刷熟。第二优先级Java基础。不需要系统的翻书直接刷真题选择题遇到不会的知识点再针对性补效率最高。第三优先级数据库和网络。这两个科目考点少且集中用一天时间集中过一遍考点再做几十道真题就够应付笔试了。第四优先级操作系统、设计模式、分布式等相关内容。有时间就看看没时间果断放弃不要因小失大。我个人当时就是因为时间安排不当在操作系统上花了不少时间背各种进程调度算法和虚拟内存细节结果考场上只出了两道基础题而操作系统在面试中的价值远大于笔试属于战略性浪费时间。6.3 关于笔试平台的适应训练牛客网笔试有几个特点跟LeetCode有显著区别一定要提前适应其一牛客网的代码编辑器比较简陋没有代码自动补全和错误提示。平时习惯了IDE自动补全的同学第一次在牛客网写代码会很不适应简单如System.out.println都可能拼错。所以备考阶段建议有意识地在牛客网的模拟笔试环境里练几道题。其二牛客网是核心代码模式和自己写输入输出模式混合。部分题目会给你一个方法签名让你实现也有部分题目需要自己解析输入。写之前先看清楚题目要求的代码模式。其三笔试过程中牛客网会全程录屏和切屏监控。如果切出浏览器超过一定次数系统会判定作弊。所以平时练习时就要养成不查资料的习惯考试时更不要抱有侥幸心理。根据我这几年的观察以及和身边同学的交流来看大厂笔试刷人比例普遍很高但淘汰的往往不是技术最差的而是准备最不充分的。携程2019届研发岗笔试难吗如果只看题本身可以说难度中等偏上没有偏题怪题全是基本功。但它的筛选意义就在于在有限时间内把基本功扎实、心态稳定、码力够强的人挑出来。你不需要考满分只要保证会做的题不丢分编程题至少AC一道进面试的希望就非常大。备考的本质是用确定性对抗不确定性。那些反复出现的考点、高频题型、固定套路就是笔试里最确定的东西把它们啃下来你离offer就不远了。