ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

58同城2016研发工程师笔试题深度拆解:基础与系统设计

58同城2016研发工程师笔试题深度拆解:基础与系统设计 58同城2016研发工程师笔试题这份标题放在今天看已经有些年头了但每年校招季都会有人把它翻出来。原因不难理解58同城作为分类信息平台的头部企业它的笔试题目设计代表了那个阶段互联网公司考察校招候选人的典型思路覆盖广、基础重、场景贴近业务。我自己当年也刷过这套题后来又断断续续帮朋友做辅导前前后后看了不下五遍。今天就把这套题拆开揉碎从考察意图、解题思路、到真正在面试中会踩的坑完整过一遍。先说说这件事对谁有用。如果你是准备校招或跳槽的研发工程师想检验自己的基础是否扎实如果你是刚入行、想建立计算机基础体系的学生或者你是面试官想参考当年的题目设计思路——这份拆解都值得你花点时间。我会把题目背后的原理讲清楚而不是只给答案。毕竟网上能找到的答案版本很多但真正值钱的是“为什么这么考”和“拿到题以后怎么建立解题框架”。1. 试卷整体画像看起来杂实则全在一个“业务”上先说结论这份试卷不是单纯的数据结构刷题库也不是纯理论八股文而是典型的“基础业务场景”混合型试卷。从题型分布来看大概可以分成四块数据结构和算法、操作系统与网络、数据库与SQL、逻辑与概率。最后往往还有一道偏综合的设计题跟58同城的业务场景绑定得很深。1.1 题型分布与考察维度先说题型分布。这套卷子一般包含选择题、填空题、简答题和编程题。选择题数量通常在20道上下覆盖范围很大从C语言指针到Java内存模型从TCP状态到进程调度都可能出现。填空题则更偏重基本功比如给一段代码让你写输出结果或者补充一个排序算法的关键步骤。简答题偏原理比如“进程和线程的区别”“索引为什么能加快查询”。编程题一般一到两道考察数据结构操作或简单算法设计。最后一题往往是系统设计或场景题比如“设计一个58同城站内搜索的热词统计模块”。这里要强调一下虽然年份是2016但它的考察维度和现在主流互联网公司的笔试题几乎没有本质区别。变化的是技术栈的比重比如当年Go和Python出现在笔试中的频率还不高Java和C是绝对的主流不变的是底层逻辑——计算机基础是否扎实、逻辑思维是否严密、是否能将基础知识迁移到业务场景中。1.2 为什么58同城会这么出题了解58同城的业务模式就能理解它为什么这么考。58同城的核心是分类信息平台覆盖房产、招聘、二手交易、本地服务等多个领域业务逻辑复杂且对高并发访问有较强依赖。这里有一个关键词信息匹配。用户发布信息、搜索信息、筛选信息这背后涉及文本处理、搜索排序、数据存储等多层技术。因此这套笔试题目在“广度”上覆盖了研发岗位必备的核心知识在“深度”上则留出了区分度。比如算法题不会难到竞赛水平但基础不牢的人会在边界条件和复杂度分析上翻车综合设计题不会要求你写出完整架构但逻辑混乱的人在组织答案时会暴露得很明显。说到底这套题的目的是筛选出“基础扎实、能解决实际问题、且有一定逻辑表达力”的候选人。我做这套题的第一个体会是不要试图用“背题”的方式去准备。题目的变体很多真正稳定的是背后的知识点和思考方式。2. 数据结构和算法不考偏题但处处是坑这部分的题目最有代表性也是网上讨论最多的。很多人觉得题目基础但做起来分数并不理想原因在于细节处理。算法题的评分不仅看“最终答案是否正确”更看“思路是否清晰边界是否考虑完整复杂度是否合理”。2.1 链表、树、排序等经典考点根据当年考生回忆汇总的题目方向链表反转、二叉树遍历、快排与归并排序的手写实现、Top K问题这类都是高频考点。逐个来说说。链表反转看起来是最基础的题但恰恰是挂人最多的题目之一。很多人能写出迭代版却说不清楚指针变化的顺序。这一步挂掉很可惜。我自己写链表题的习惯是先画图再写代码。画图能让你明确每个节点在某一时刻被谁指向、它自己又指向谁。迭代反转的核心是三个指针——prev、cur、next每轮循环先把next暂存下来再断链、改向、移动。很多人在这里少写一步“移动指针”死循环就出来了。二叉树的中序遍历则是考察递归和非递归两种写法。递归版简单但非递归版能真正体现你是否理解栈在遍历过程中的作用。用栈模拟中序遍历时规则是“沿着左子树一路压栈左子树为空时出栈访问然后转向右子树”。这里有个非常关键的条件当节点弹出并访问后要立即将当前指针指向它的右孩子而不是继续弹出栈顶。很多初学者在这个地方逻辑混乱导致输出顺序错误。针对2016年的笔试题面试官考非递归写法意图明显——考察候选人对栈这种数据结构的理解深度绝不只是会用递归就行。再说排序。快排和归并排序几乎是必考。快排的考点在partition函数它不仅要返回pivot的正确位置还要保证左边都小于等于pivot、右边都大于pivot。写partition时有个小技巧选右端点作为pivot用i标记小于等于pivot的区域的右边界从左往右扫描遇到比pivot小的元素就和i位置交换。这里要特别注意的是如果pivot选择不当比如有序数组选固定端点会触发最坏时间复杂度O(n²)所以在实际工程中会用“三数取中”来规避。面试时主动提这一点是加分项。Top K问题也常出现。比如“从海量数据中找出最大的K个”。这类题的考察点不在堆排序本身而在于候选人是否能根据数据规模选择合适的方法。如果数据量小直接排序取前K就完了数据量很大无法全部加载进内存时才需要用一个大小为K的小顶堆做单遍扫描。但有些候选人一上来就堆排序连数据规模都不问这就是典型的“没有业务sense”。实际上面试官期待听到的答案应该是先问清楚“数据量多大K有多大能否一次加载进内存”再给出对应方案。2.2 动态规划与贪心怎么判断用哪种算法动态规划题在2016年的试卷里也有涉及通常不会太难比如最长公共子序列、编辑距离、背包问题这类经典模型。考察点通常是两个状态定义是否正确、状态转移方程是否写得清晰。以最长公共子序列为例定义dp[i][j]为“字符串A的前i个字符与字符串B的前j个字符的最长公共子序列长度”。转移时如果A[i-1]等于B[j-1]那么dp[i][j] dp[i-1][j-1] 1否则dp[i][j] max(dp[i-1][j], dp[i][j-1])。这个模型背下来不难难的是遇到变体时能识别出来。判断一道题该用动态规划还是贪心有一个简单但不完全严谨的方法看问题是否具备“最优子结构”和“重叠子问题”。如果子问题的最优解能推导出全局最优解并且子问题会重复出现那就优先考虑动态规划。贪心则要求每一步的局部最优选择最终能导向全局最优这需要严格的贪心策略证明不能靠感觉来。比如“找零钱问题”的硬币系统如果是普通情况用动态规划才是稳妥的只有在硬币面额是特殊设计时贪心才成立。2016年的笔试题里有类似的混淆项就是在题干里埋了一个“看似无脑贪心但实际要动态规划”的案例专门区分应试者是否理解两者区别。再说一个很多过来人会忽略的点笔试中的算法题不要求写出“最优解”才能通过。能写出一个时间复杂度正确但常数较大的方案往往比写一个理论上更快但漏洞百出的方案得分更高。因为在线评测系统会同时考察正确性和超时风险如果一个O(n²)的暴力解能跑满所有测试数据它得到的分数并不低。所以在笔试时先写出一个能保证正确的解法再去优化是更务实的策略。3. 操作系统与网络这些题答不好算法再强也白搭这套试卷里操作系统和计算机网络的比重相当大而且主观题居多——不少是“请描述一下”“什么情况下会发生”这类要求理解而不是背诵的题。很多候选人觉得这部分是死记硬背其实恰恰相反操作系统和网络的考点全部是“原理驱动”的。你理解了机制怎么问都能答你只是背了答案换个问法就懵。3.1 进程线程与并发问题进程与线程的区别是基础中的基础。如果只回答“进程是资源分配的基本单位线程是CPU调度的基本单位”这只能拿及格分。要拿高分得补充以下几点进程拥有独立的地址空间一个进程崩溃不会直接影响其他进程线程共享进程的地址空间线程间通信成本低但一旦共享数据没做好同步就会出现并发问题。所以真正的高分答案是先说定义再说资源分配区别最后落到“通信与同步的代价”上。进程间通信IPC方式也是常见考点。管道、消息队列、共享内存、信号量、Socket这类最好能分点讲清楚各自的特征和适用场景。管道适合父子进程之间的简单数据流消息队列适合单向消息传递共享内存是效率最高的IPC方式但需要配合信号量解决同步问题。面试时如果能举一个实际场景来说明如何选择比如“两个服务之间做实时数据同步选什么进程间通信方案”会比单纯背诵概念好得多。线程同步问题也考得不少。经典的“生产者—消费者问题”几乎年年出现。表面上是考PV操作或锁的应用实际上考察的是对“竞态条件”和“死锁”的理解。写答案时要强调两个要点控制缓冲区访问的锁以及协调生产者、消费者顺序的条件变量。两者缺一不可。只加锁不唤醒消费者可能永远等不到数据只唤醒不加锁缓冲区状态可能被破坏。3.2 TCP三次握手与HTTP状态码网络部分的必考题就是TCP三次握手、四次挥手以及为什么需要这些状态转换。三次握手的过程大家都背得出来但有几个细节容易被忽略。比如第二次握手前服务器会进入SYN_RCVD状态第三次握手完成后连接才真正建立。为什么需要第三次握手因为要防止“已失效的连接请求报文段”突然又传到服务器导致服务器端误建立连接。这个解释能体现你真正理解了TCP设计的原因而不是只会背状态名。四次挥手比三次握手更复杂因为涉及半关闭状态。主动关闭方发出FIN后进入FIN_WAIT_1收到ACK后进入FIN_WAIT_2等待被动关闭方也发出FIN被动关闭方收到FIN后先回ACK然后继续把剩余数据处理完再发出FIN最终主动方进入TIME_WAIT状态。关于TIME_WAIT需要掌握两个关键点一是等待时长是2MSL确保最后一个ACK能到达对方二是有大量TIME_WAIT连接堆积时可能耗尽本地端口需要调整内核参数或复用连接。最后这点在58同城这种高并发业务场景里尤其重要因为短连接请求量大TIME_WAIT问题很常见。HTTP状态码也考得很细。比如301和302的区别——301是永久重定向302是临时重定向403和404的区别——前者是服务器理解请求但拒绝执行后者是资源根本不存在。很多人会把500和502搞混500是服务器内部出错了502是网关或代理从上游服务器收到了无效响应。如果面试官追问“502通常由什么引起”能说出“上游服务挂了或者响应超时负载均衡器返回502”就非常加分。关于网络这块我有个真实的教训当年我自己复习时分不清TCP的拥塞控制和流量控制笔试时遇到简答题答案写得模棱两可。流量控制是点对点的解决“接收方处理不过来”的问题通过滑动窗口机制实现拥塞控制是全局性的解决“网络中间设备处理不过来”的问题通过慢启动、拥塞避免、快重传、快恢复来实现。这两个概念特别容易被混在一起。建议复习时一定把机制、动机和解决对象三者结合起来记忆不要孤立地背名词。4. 数据库与SQL考察的是“设计思路”而不仅是语法数据库题目在这套卷子里也占了大头而且题型非常“业务化”。它不满足于让考生写一条SELECT语句而是要求理解索引的原理、掌握SQL优化的思路、甚至要能设计表结构来支撑业务场景。这一点和58同城这种依赖数据库进行大量数据读写的业务是分不开的。4.1 索引与查询优化的底层逻辑索引是必考项。高频问题包括索引为什么能提速底层用的什么数据结构什么时候该建索引什么时候不该建B树为什么适合作为索引结构先说B树。相比B树B树把所有数据都存放在叶子节点并且叶子节点之间通过指针相连。这带来的好处有两个第一非叶子节点可以存储更多的键树的高度就能更低查询次数减少第二叶子节点用链表串联起来做范围查询时非常高效直接沿着链表遍历就行不需要回到上层节点。这也是MySQL InnoDB选择B树作为默认索引结构的重要原因。再说不该建索引的场景。很多候选人知道“经常被查询的字段要建索引”但不知道“频繁更新的字段最好不要建索引”。因为每一次INSERT或UPDATE除了修改表数据还要同步更新索引结构。字段更新越频繁索引维护的开销越大。如果在低选择性的字段上建索引比如性别字段只有“男”“女”两个值索引带来的查询提升非常有限反而白白增加维护开销。回答索引问题时如果能主动提出“选择性”这个概念就会明显拉开与其他候选人的差距。SQL优化题比原理题更好得分但也很容易失分。常见问题是“有一张非常大的订单表查询某个用户的最近10条订单记录很慢怎么优化”答案可以从多个层面切入先确认查询条件是否走索引如果没走用EXPLAIN看一下如果查询涉及多表关联小表驱动大表会更高效如果只是统计类业务考虑建缓存表或汇总表。另一个常见优化点是避免SELECT *明确列出所需字段减少IO开销。4.2 一道经典SQL题的多种写法这里根据当年考生的回忆复原一道代表性的SQL题有一个员工表employee(id, name, department_id, salary)要求查出每个部门中工资最高的员工信息。最直观的写法是子查询先查出每个部门的最高工资再关联员工表。SQL大致长这样SELECT e.* FROM employee e INNER JOIN ( SELECT department_id, MAX(salary) AS max_salary FROM employee GROUP BY department_id ) t ON e.department_id t.department_id AND e.salary t.max_salary;这个写法没问题但局限在于如果一个部门里有两个员工工资并列最高结果会返回两行。如果在某些场景中希望“每个部门只返回一个人”就需要用到窗口函数比如用ROW_NUMBER()按工资排序并给每组编号再取出编号为1的记录SELECT * FROM ( SELECT e.*, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn FROM employee e ) tmp WHERE rn 1;注意这里使用了ROW_NUMBER而不是RANK区别在于并列排名时ROW_NUMBER会强制分出先后而RANK会保留并列结果。笔试时能写出这两种方案并解释清楚它们的差异基本上就把这道题的分数拿稳了。这里要特别提示一个笔试环境常见的坑有些在线笔试系统不提供MySQL 8.0以上的环境窗口函数可能不支持需要用子查询方案。拿到SQL题先明确数据库版本和可用的函数集合再决定写法这是成熟工程师的表现也是基本业务意识。4.3 表设计题从业务反推动态模型有一道表设计题值得单独拿出来说它往往给一个贴近58同城的业务场景比如“设计一个二手商品发布、搜索、分类浏览的数据库模型”。这道题考的是候选人能否从零开始把业务逻辑转成表结构。基本思路是先画核心实体用户表、商品表、商品分类表。再理关联关系用户和商品是一对多商品和分类是多对一。接下来考虑扩展需求商品有图片图片需要单独建一张表还是直接放URL字段商品有浏览量和上下架状态这些状态字段放哪搜索要对标题做模糊匹配应该建索引还是引入搜索引擎一个容易出错的点是商品分类的层级设计。如果分类只有一级一个category_id字段就够了如果有多级分类最方便查询的设计是使用“闭包表”或“路径枚举”方式而不是简单的父子字段递归查询。多数候选人在此会纠结但如果在标准回答中提出“分类可能有多级所以我会为分类表增加parent_id字段查询时用递归CTE获取子分类”这一下子就脱颖而出了。表设计题没有标准答案但评分点在于“边界是否覆盖完整、字段选择是否合理、是否考虑了业务扩展性”。不要一上来就写表结构先把业务对象画出来再逐步展开这个思考过程本身就是面试官想看到的。5. 逻辑题与概率题不止是脑筋急转弯很多研发岗位的笔试都会放几道逻辑题和概率题这套卷子也不例外。这类题目的权重一般不高但性价比很高——因为大部分人会在这些题上浪费时间如果你能快速找到解法反而能节省时间给后面的编程题。5.1 n条线划分平面的递推思维先还原一道经典的逻辑题n条直线最多能把一个平面划分成多少个区域这道题的本质是递推。新增第n条直线时如果它与前面n-1条直线都相交并且交点不重合那么它会被分割成n段每一段把原有区域一分为二新增n个区域。所以递推公式是f(n) f(n-1) n初始f(0) 1。解这个递推式得到f(n) n(n1)/2 1。如果题目再延伸一点问n个圆最多能把平面划分成多少区域思路类似但递推系数不同。新增第n个圆时它与前面n-1个圆最多有2(n-1)个交点这些交点把新圆分成2(n-1)段弧每段弧新增一个区域所以递推公式是g(n) g(n-1) 2(n-1)。这类题的共同点是不要试图画图而是用“新增元素带来了多少新增区域”来思考。5.2 概率题只考基础模型概率题一般不会出太复杂的贝叶斯推理更多是古典概型或简单的条件概率。比如经典的“有两个孩子已知其中一个是女孩求另一个也是女孩的概率”——正确答案是1/3而不是1/2。关键在于样本空间是“男女、女男、女女”三种等可能情况已知其中一个是女孩时排除“男男”剩下三种情况中等可能的只有一个“女女”所以概率是1/3。这类题目有个共同的答题技巧不要凭感觉写下答案先把所有等可能的样本空间写清楚再按条件过滤。写清楚样本空间本身就能拿到不少分面试官看重的是严谨性而不是最终数字是否正确。如果题目涉及“不放回抽样”或“放回抽样”一定要先明确属于哪种区别会直接影响概率计算。5.3 时间管理与取舍策略逻辑题虽然分值不高但搞心态的能力特别强。我的经验是拿到试卷后先把所有题目快速扫一遍标记出逻辑题和概率题的位置如果一道题想了超过三分钟还没有清晰的思路果断先跳过等所有题目做完以后再回头来啃。这套试卷的编程题往往放在最后如果被前面的逻辑题拖住编程题没做完反而得不偿失。6. 综合设计题把基础能力投射到真实业务上这部分是58同城笔试题的重头戏通常放在试卷末尾。它考察的不再是单一知识点而是一个工程师面对复杂业务场景时的整体思考能力。从历年考生反馈来看综合设计题往往出现“搜索关键词统计”“热点信息监控”“消息推送系统”这类业务方向。6.1 一道贴近业务的系统设计题热词统计模块假设题目是“设计一个58同城站内搜索热词统计模块统计周期为一小时要支持实时查询TOP100热词。要求说明存储选型和链路设计。”这个题没有标准答案但有几个关键点是面试官期待听到的。首先是数据链路。用户每次搜索都会产生一条日志需要采集这些日志并传输到统计系统。可以用消息队列做缓冲比如Kafka搜索服务把日志写入Kafka统计服务消费Kafka里的数据进行实时计算。提到Kafka时顺带说明“它起到削峰填谷的作用防止流量高峰打垮统计系统”这就是业务敏感度。其次是计算方法。一小时内的热词统计最简单的方案是“滑动窗口”但需要精确控制窗口边界。可以用“时间轮”或者“布隆过滤器 计数器”的组合方案。这里的核心问题是同一个用户重复搜索同一个词算一次还是多次这需要与产品侧确认但笔试时你可以先说“默认按搜索次数统计如果需要考虑去重可以按用户维度做去重”这样展现出业务的缜密性。最后是存储与查询。热搜TOP100需要实时更新数据量不大可以直接用Redis的Sorted Set存储key是热词字符串score是搜索次数。实时统计时更新ZSet查询时用ZREVRANGE取前100个。由于这个操作非常高频建议给ZSet加一层本地缓存比如在统计服务内存中缓存最近一次的TOP100结果并设置几秒的过期时间减少对Redis的读压力。6.2 面试官真正想听到怎样的回答这道题能拿高分的关键不在方案本身而在于“不遗漏环节”。一道系统设计题通常包含数据采集、数据计算、数据存储、数据查询这四个环节。很多候选人的方案只覆盖了其中两三个而没有形成链路闭环。另外不要忽略异常场景。面试官如果追问“如果Kafka集群挂了怎么办”“如果Redis内存满了怎么办”不要慌。这些问题没有统一答案但核心是考察你有没有“降级方案”的意识。比如Kafka挂了可以先落本地日志等Kafka恢复后再做补偿推送Redis内存不够可以淘汰低频词或者把一周前的数据归档到数据库。能说出这些方案即使不完美也比沉默不语或死记硬背的系统设计模板强得多。我自己在复习系统设计时有个习惯不追求画出唬人的架构图而是用文字把数据流“从A到B再到C”说清楚。你能用简洁的语言讲清楚数据是怎么流转的、每个环节存什么数据、遇到故障怎么办对方就能判断出你是真理解还是背模板。7. 用这份真题准备面试的正确姿势一套好的笔试题不只是用来检测能力的工具更是很好的复习提纲。尤其是面对“58同城2016研发工程师笔试题”这样的内容如果你能把它背后的知识点都吃透应付大量类似风格的互联网公司笔试都不会太慌。7.1 按知识点建立复习节奏不要拿到题目就刷先花半天把试卷涉及的知识点列成清单数组、链表、树、图、动态规划、操作系统进程线程、网络TCP/IP、HTTP、数据库索引与SQL优化、缓存、消息队列、系统设计。然后用每个知识点去检索自己的薄弱项。具体复习节奏上我的建议是分三轮。第一轮按章节过基础把每一个考点的原理搞清楚这一轮不追求做题量而是建立知识框架。第二轮按题目类型刷题每道题都要写出详细的解题过程和复杂度分析。第三轮做整套卷子的限时模拟严格控制时间训练自己在笔试环境下的节奏感。这里特别提一点笔试答题是有技巧的尤其是编程题。在线编程环境中的调试功能往往不如本地IDE方便而且输入输出格式经常有坑。进入笔试系统后先花三分钟看清楚“输入输出格式要求”“是否支持代码补全”“是否有自动保存”这些细节看似无关紧要实际对答题舒适度影响巨大。很多候选人栽在“没有正确读取多行输入”这种低级问题上一旦格式错误哪怕算法写对了也拿不到分非常可惜。7.2 真题之外的扩展建议笔试只是第一关后面还有面试环节。2016年的这套卷子在面试中衍生出的追问几乎都集中在“你写的答案是否真的理解了”。比如SQL题写完后面试官大概率会问“你这个查询会走索引吗EXPLAIN的结果是什么”系统设计题写完后会问“这个方案的瓶颈在哪里怎么扩展”所以复习时不要只听懂答案要追着问自己这个方案的短板是什么还有没有更好的方案我建议准备一份自己的错题本把踩过的坑记录下来。比如我自己曾经在实现快排时递归深度过大导致栈溢出在写SQL时忽略了索引失效的条件在设计系统时忘记了数据一致性问题。记录这类错误比刷十道新题都管用。它让你在面试前能快速回看自己的薄弱环节做到心中有数。另外现在再看2016年的题目有一个明显的时代背景那正是移动互联网和O2O行业高速扩张的时期58同城发力本地生活服务对研发人才的需求量很大所以笔试的风格更偏重“工程落地能力”。今天的笔试趋势则更强调分布式、容器化、云原生等新技术栈的认知。但无论题型怎么变数据结构、操作系统、网络、数据库这四大基础板块始终是互联网公司研发岗笔试的核心。把这份2016年的真题吃透了你就等于摸清了这类考试的底层逻辑。要说我心里话我觉得备考阶段最忌讳的就是把精力全放在“猜题”上。技术面试的本质不是看你记了多少答案而是看你在现场能不能把学过的东西灵活组合起来。扎实过一遍基础比每天刷几十道但从不复盘要有效得多。最后再分享一个我实际辅导中反复用的小技巧每次做完一道笔试题给自己提三个问题。第一这道题涉及哪些基础知识点第二如果数据量扩大十倍我的方案还成立吗第三如果我是面试官我会追问什么把这三个问题想清楚一道题就真正变成你自己的东西了。这套方法不仅适用于58同城2016研发工程师笔试题也适用于几乎所有技术笔试。你可以试试看。
返回列表