十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

爱奇艺研发工程师笔试题复盘:从C++基础到算法与系统设计

爱奇艺研发工程师笔试题复盘:从C++基础到算法与系统设计 爱奇艺2016研发工程师笔试题放在今天看确实有点年份感但如果你正准备互联网公司的研发岗笔试这份题还是很典型的复习样本。2016年前后正是视频网站技术团队扩张最猛的阶段爱奇艺的笔试题带着很明显的“业务与基础并重”的印记既考C内存模型、网络协议这些基本功也考字符串处理、链表操作这类高频编程题偶尔还会插入一两道跟视频业务相关的场景题。这篇文章适合两类人看。第一类是准备大厂研发岗笔试的应届生可以用来对照当前复习节奏查漏补缺第二类是工作两三年想跳槽的工程师可以用它快速回炉基础知识点顺便检验一下自己是不是把大学里学的东西都还给老师了。我会按题型把题目拆开讲包括考察意图、解题思路、手写代码和实际踩坑经验。1. 这份笔试题究竟考什么整体定位与考察逻辑1.1 爱奇艺笔试的行业底色与出题风格很多人拿到笔试题的第一反应是刷题但我觉得先搞清楚出题人想要什么比盲目刷题更重要。2016年爱奇艺的研发笔试题跟当时其他一线互联网公司比有个明显特点基础题占比很高业务题也偏工程化基本不会出那种偏题怪题。为什么这样出题一方面视频网站的业务场景对稳定性要求极高用户看视频看到一半崩溃体验损失比普通网页大得多所以招聘时特别看重候选人有没有扎实的底层功底。另一方面2016年视频行业正处于移动端爆发期高并发访问、播放体验优化、个性化推荐这些都是当时的技术重点笔试题自然也会往这些方向靠。这告诉我们的备考逻辑其实很简单核心技术基础够不够硬决定了笔试能不能过有没有工程思维和业务敏感度决定了面试官愿不愿意给你下一轮机会。1.2 笔试考察的四个能力维度爱奇艺这套题看似零散实际上可以归纳成四个维度。第一个是语言基础C/C是重点特别是内存管理、指针、虚函数、构造析构这些因为客户端播放器和部分服务端模块都用C这些知识点直接关系到底层稳定性。第二个是数据结构与算法字符串反转、链表操作、二叉树遍历、排序算法都属于必考范围笔试环节算法题占比大约三分之一手写代码的基本功在这里会被看得一清二楚。第三个是操作系统与网络进程线程区别、死锁条件、TCP三次握手、HTTP状态码这些经典问题几乎每次笔试都会遇到。第四个是业务场景题这类题在2016年爱奇艺的笔试里已经出现了比如视频播放卡顿怎么排查、热门视频如何设计缓存都属于“给你一个真实问题看你怎么拆解”的路子。1.3 这份题适合谁来参考如果你正在准备校招笔试这套题可以作为中期复习的测评卷。我的建议是先不要看答案给自己定一个半小时的计时完整做一遍感受一下时间压力再对照解析看自己卡在哪类题目上。如果你已经工作了一段时间这套题的价值在于查漏补缺。我见过不少工作两年以上的工程师写业务代码很溜但让他说清楚“进程和线程的本质区别”或者“为什么TCP要三次握手”反而讲不完整这类基础漏洞在跳槽笔试时很容易暴露。2. 真题复盘基础理论与概念题拆解2.1 常考题型分布速览先看整体分布。根据当时多家培训机构整理流传的笔经爱奇艺2016研发工程师笔试题大致可以归为以下几类。题型数量占比考察重点单选题30%左右语言基础、操作系统、网络常识不定项选择15%左右边界条件、概念辨析、代码输出结果编程题35%左右数据结构、算法设计与手写实现简答/场景题20%左右视频业务、系统设计、问题排查思路这个分布说明选择题和编程题几乎是半壁江山纯背诵型知识点占比不高更多是理解型和应用型考察。2.2 典型单选题C虚函数与内存布局有一道很经典的单选题问的是“含有虚函数的类实例化后的对象内存中第一个成员是什么”。答案是虚函数表指针也就是vptr通常占4字节32位系统或8字节64位系统位于对象内存布局的最前面。这道题表面考虚函数实际考的是C对象模型的理解。很多刷面经的人背过“虚函数表”这几个字但不清楚为什么对象里要存一个指向虚函数表的指针。简单解释一下C支持多态靠的是运行时动态绑定当通过基类指针调用一个virtual函数时编译器并不知道实际对象是哪个子类只能在运行时去查虚函数表才能确定应该调用哪个版本的函数。这个查询动作就是“动态绑定”而查询的入口就是对象内存里那个隐藏的vptr。我当年复习的时候喜欢自己画一下内存布局图把基类和子类的vptr、成员变量排列画出来比背十遍概念都管用。2.3 典型选择题数组与指针的关系陷阱还有一道高频题大概长这样给定int a[5]请问(a 1)表示什么如果你直接想成“数组首地址加1”那这道题就错了。a是整个数组的地址类型是int(*)[5]所以a 1跳过的不是一个int而是整整5个int也就是跳过了整个数组。这里面的核心陷阱是区分“数组首元素的地址”和“数组的地址”这两个概念。a在大多数表达式中会退化为指向首元素的指针但a始终是指向整个数组的指针两者的步长完全不同。这类题在笔试里出现频率极高不完全是因为爱奇艺爱考而是因为它是考察C语言底层理解的一个经典切片很多工作了几年的人都容易答错我把它当作“基本功试金石”来看。2.4 不定项选择题进程线程与死锁不定项选择的典型代表是“下列关于进程和线程的说法哪些是正确的”。正确选项一般包括进程是资源分配的基本单位线程是CPU调度的基本单位同一进程内的线程共享地址空间不同进程的地址空间相互隔离。容易选错的干扰选项是“线程切换一定比进程切换快”和“线程可以完全替代进程”。为什么“线程切换一定比进程切换快”不对因为线程切换虽然不用切换地址空间但还是要保存和恢复寄存器上下文、程序计数器等如果两个线程不在同一个CPU核心上还可能涉及缓存失效。而且进程切换的代价里很大一部分是页表切换和TLB刷新这些在线程切换中确实可以避免但绝对不能推出“一定比进程快”。这类题目用的就是绝对化表述作为陷阱。同样的逻辑也出现在死锁题里。考死锁条件的时候记得是四个必要条件互斥、占有且等待、不可抢占、循环等待。题目如果问“破坏哪个条件可以有效防止死锁”答案通常是从“占有且等待”或“循环等待”入手比如资源一次性分配、按序分配等。2.5 网络与系统三次握手和HTTP状态码网络题里TCP三次握手几乎是必考。选择题一般考握手的顺序和标志位比如SYN、SYNACK、ACK简答题则可能让你说明“为什么需要三次握手而不是两次”。这个问题的标准解释是三次握手能确保双方都确认自己和对方的收发能力正常。第一次客户端发SYN服务器知道客户端发能力正常第二次服务器回SYNACK客户端知道服务器收能力正常、发能力也正常第三次客户端回ACK服务器知道客户端收能力正常。如果只有两次握手服务器无法确认客户端的接收能力可能导致已经失效的连接请求突然到达服务器白白建立一条空连接。HTTP状态码也是高频考点。我建议至少记住200正常、301永久重定向、302临时重定向、304未修改缓存相关、400请求错误、401未认证、403禁止访问、404不存在、500服务器内部错误、502网关错误、503服务不可用。爱奇艺这种视频站点用户会频繁触发缓存和重定向逻辑所以304、301、302这几个状态码在业务场景里会特别常见。3. 核心算法题的思路与手写实现3.1 字符串类题目的考场解法字符串处理是当年爱奇艺笔试编程题的大头常见的有字符串反转、括号匹配、最长公共前缀、字符串去重等。难度不高但非常考验边界条件处理能力。举个例子反转字符串中的单词顺序要求单词内部字符顺序不变比如输入the sky is blue输出blue is sky the。很多人第一反应是先按空格切分再逆序遍历拼接但要注意连续多个空格的情况。LeetCode原题的官方解法是先把整个字符串反转再逐个反转每个单词我在笔试里也推荐这种做法因为原地处理空间复杂度是O(1)。def reverse_words(s: str) - str: s s.strip() words [] i 0 n len(s) while i n: while i n and s[i] : i 1 start i while i n and s[i] ! : i 1 if start i: words.append(s[start:i]) return .join(words[::-1])笔试改卷时最看重的是边界条件比如字符串为空、全是空格、只有一个单词、首尾都有空格。我见过不少同学能写出核心逻辑但因为没处理首尾空格被扣分非常可惜。3.2 链表题反转与环检测链表在笔试编程题里的地位极高原因很简单实现链表的代码不长但能考察指针操作、递归思维和边界条件处理信息密度很高。两道必练题是“反转链表”和“环形链表检测”。反转链表用迭代法最稳三指针prev、curr、next依次反转注意循环结束后要把原来的头结点的next置空否则会产生环。struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(nullptr) {} }; ListNode* reverseList(ListNode* head) { ListNode* prev nullptr; ListNode* curr head; while (curr ! nullptr) { ListNode* next curr-next; curr-next prev; prev curr; curr next; } return prev; }环形链表检测最经典的是快慢指针法fast指针每次走两步slow指针每次走一步如果有环两者必然相遇。我当时踩过的坑是忘记处理空链表和单节点链表的情况fast-next空指针访问会直接崩溃笔试环境不像本地IDE那么好调试所以开始写之前一定要先把特殊情况列出来。3.3 二叉树遍历与层级输出二叉树题目在2016年爱奇艺笔试中也出现过。最基础的是前中后序遍历的递归实现但笔试往往不会只考递归更多会考非递归和层序遍历。层序遍历有一个常见变形要求按层级分组输出比如第一层一个列表第二层一个列表。很多人的第一反应是直接队列遍历但这样分不清层级边界。正确做法是每次循环先记录当前队列的长度然后只处理这个长度个节点这样就天然分好了层级。vectorvectorint levelOrder(TreeNode* root) { vectorvectorint result; if (!root) return result; queueTreeNode* q; q.push(root); while (!q.empty()) { int levelSize q.size(); vectorint level; for (int i 0; i levelSize; i) { TreeNode* node q.front(); q.pop(); level.push_back(node-val); if (node-left) q.push(node-left); if (node-right) q.push(node-right); } result.push_back(level); } return result; }笔试中这类题目的考察重点不是你会不会递归而是你会不会在递归之外换一种思路。平时练题的时候我建议有意识地把每道递归题都写一遍非递归版本练的是栈和队列的灵活运用这个习惯对面试手撕代码也很有帮助。3.4 动态规划最长递增子序列动态规划在笔试里属于区分度高的题型爱奇艺这类视频公司还涉及推荐、个性化排序等场景动态规划出现频率不低。最长递增子序列LIS就是典型题目。最经典的写法是O(n^2)的DPdp[i]表示以nums[i]结尾的最长递增子序列长度转移时遍历i之前的所有j如果nums[j] nums[i]状态转移方程为dp[i] max(dp[i], dp[j] 1)。def length_of_lis(nums): if not nums: return 0 n len(nums) dp [1] * n for i in range(n): for j in range(i): if nums[j] nums[i]: dp[i] max(dp[i], dp[j] 1) return max(dp)O(n^2)写法思路直白适合笔试因为代码不容易出错。如果你追求更高性能可以用贪心加二分维护一个tails数组把时间复杂度降到O(n log n)但实现难度会大一些。我的建议是笔试时先写最稳的版本把正确率保住时间允许再优化。万一面试官要求优化再展示你在O(n^2)基础上的进阶思路效果反而更好。4. 场景题与业务题视频网站工程思维的模拟4.1 从用户点击到视频播放排查题怎么答爱奇艺的笔试里场景题通常不像算法题那样有标准答案但回答得好不好一眼就能看出你是有工程经验还是只会背题。一道很典型的场景题是“用户在App里点开一个视频播放卡顿请描述你的排查思路。”如果你只回答“可能是网络不好”这道题基本就废了。好的回答要有层次感。我的回答框架是先分段再排查。第一步确认是偶发还是必现如果必现问题大概率在服务端或视频源如果偶发优先怀疑网络。第二步检查客户端到CDN节点的网络质量包括丢包率、RTT、DNS解析耗时可能的话用抓包工具看有没有大量TCP重传。第三步看播放器状态是首屏加载慢还是播放中频繁卡顿两者对应的问题可能完全不同前者可能跟首包耗时有关后者可能跟缓冲策略、码率切换有关。第四步看服务端检查视频转码格式、切片大小、CDN命中率、源站负载。这些排查点在笔试里不需要写得很深但要让阅卷人看到你有完整的排查链路而不是零散地猜原因。4.2 热门视频榜单缓存与排序设计另一类场景题是“如何设计一个热门视频排行榜”。这类题在视频公司出现完全合理而且没有唯一答案考察的是你能否结合业务场景做合理取舍。核心思路是“写入时计数、读取时聚合”。用户观看行为会产生大量的播放日志如果每次播放都直接更新数据库的计数器数据库压力会很大。更稳妥的方案是先把播放事件写入消息队列后台异步消费定期聚合到Redis里排行榜直接从Redis读取。具体到排序维度常见的有播放量、完播率、点赞数、分享数也可以做加权综合分比如score 播放量 * 0.5 完播率 * 0.3 互动量 * 0.2。这里要注意“时间的衰减”一个三天前爆火的视频和一个三小时前爆火的视频即使播放量相同热度也不一样可以用类似Hacker News的算法用发布时间对分数做降权。笔试里答这类题关键是展示你有“分层”的思维接入层、处理层、存储层各司其职而不是把一大堆功能堆在一个模块里。哪怕是简单的文字描述也要体现出“我知道哪里是瓶颈、哪里要加缓存、哪里要异步化”的工程判断。4.3 日志收集与布隆过滤器视频网站的访问日志量非常大笔试偶尔会考一个衍生问题“如何判断一个URL是否已经在今天的日志中出现过”如果直接存HashSet每个URL几字节上亿条数据就是几个GB内存服务端显然扛不住这时候可以用布隆过滤器。布隆过滤器的原理很简单一个位数组加多个哈希函数插入元素时把多个哈希位置置1判断元素是否存在时检查这些位置是否都为1。如果有任何一个位置为0元素一定不存在如果全部为1元素可能存在也就是有误判率。误判率可以通过位数组大小和哈希函数数量来调节。优缺点也明显。优点是空间效率极高缺点是没法删除元素且存在误判。在笔试里讲清楚“为什么用布隆过滤器”以及“误判率如何权衡”比背出实现代码更重要。我当时复习时总结过一句话布隆过滤器适合“允许小概率误判但绝不允许漏判”的场景比如URL去重、黑名单过滤都符合这个特征。5. 备考路径与常见问题排查5.1 复习优先级建议结合爱奇艺这套题和同类企业笔试题的出题特点我建议准备研发岗笔试的同学按照下面这个顺序安排复习。第一优先级是数据结构与算法包括数组、字符串、链表、栈、队列、二叉树、哈希表以及排序、二分查找、双指针、动态规划这些核心算法。笔试的绝对大头在这里编程题能不能写出来直接决定你能不能进入面试环节。第二优先级是语言基础如果你主攻C虚函数、内存管理、STL底层原理、智能指针都要过一遍如果你主攻JavaJVM内存模型、集合框架、并发编程要重点关注。第三优先级是操作系统和网络的核心概念不需要抠太细但进程线程、死锁、内存管理、TCP/UDP、HTTP这些高频考点要能讲清楚。第四优先级是场景题和业务常识这部分可以结合目标公司的业务特点来准备比如投视频公司就想想视频播放链路、CDN、排行榜这些场景。5.2 考场时间分配与做题节奏笔试时间通常很紧张我见过太多人因为时间分配不当编程题没写完或者最后几道选择题草草蒙完。我的建议是拿到卷子先花两分钟扫一遍全卷搞清楚大题的题量和难度心里有个底。具体节奏上选择题控制在每道题一分半以内不会的先标记跳过不要恋战。编程题每道至少预留20到30分钟如果15分钟内一点思路都没有果断换下一道最后再回来啃硬骨头。场景题一般留10到15分钟不需要写太多字但要把框架写清楚。这里提醒一个关键习惯写代码前先在草稿纸上梳理思路和边界条件不要直接上手敲。很多人一紧张就直接写写到一半发现思路错了改来改去浪费大量时间反而得不偿失。5.3 高频失误与针对性改进我总结一下笔试题里最容易丢分的几个点算是给后来人排雷。第一边界条件处理不完整。空数组、单元素数组、全是重复元素、链表只有一个节点、根节点为空这些特殊情况必须在写完代码后主动检查。第二复杂度分析写不清楚。编程题如果要求说明时间复杂度和空间复杂度常常有同学写错比如把二分查找写成O(n)明显是概念没掌握。第三代码可读性差。变量名用a、b、c不是不行但关键逻辑处至少要有注释笔试阅卷很多环节是人工看的代码整洁度会影响印象分。我当年还吃过一个亏就是写完代码不检查数组越界。笔试环境不像本地IDE有清晰的运行时提示有时候数组越界不会立刻崩溃而是产生一个奇怪的结果这种错误最难查。所以每次写完循环我都会手动跑一个小例子把循环变量的变化过程走一遍确认不会越界再提交。5.4 常见问题速查表为了让你复习时方便对照我把这套题暴露出的高频问题整理成一个速查表。问题错误理解正确理解虚函数机制虚函数表存在对象里对象里存虚函数表指针虚函数表一般存在于只读数据段数组名退化a和a完全等价a指向整个数组a通常指向首元素线程切换线程切换一定比进程切换快不一定要分场景但通常线程切换开销更小TCP握手次数两次握手就够了三次才能确保双方收发能力都确认死锁条件有循环等待就一定死锁死锁必须同时满足四个必要条件进程同步线程之间无法同步可以通过信号量、锁等机制同步但要注意死锁动态规划只求dp数组最大值要明确dp数组的含义和转移方程CDN作用加速所有网络请求主要加速静态资源分发动态请求回源成本高6. 一点个人经验为什么现在还要看这份旧题聊到这儿可能有人会问2016年的题现在还有什么参考价值我的看法是研发工程师笔试的底层层面的知识点迭代速度没那么快。很多算法题和基础概念题在今天的笔试里依然是变形出现比如反转链表、字符串处理、二叉树遍历换个措辞换个包装内核不变。我看这类旧题的主要价值有三个。第一个是摸底找一套完整的旧题限时做一遍比盲目刷几十道零散题目更能准确知道自己的水平。第二个是练题感旧题往往没有过度加难度用来建立信心和熟悉笔试节奏很合适。第三个是理解“公司想要什么人”出题风格能反映公司技术文化的倾向爱奇艺这套题呈现的务实风格在那个年代算很有代表性的。我个人的体会是复习笔试最重要的不是题海战术而是把每道题背后的知识点彻底吃透。一道反转链表你能讲出迭代和递归两种写法能分析空间复杂度差异能处理带头结点和不带头结点的变体那这道题才算真正会了。做十道题却一知半解远不如做一道题把一个知识点完全啃透后者在笔试里的实际效果要好得多。最后再分享一个小技巧每次做完一套笔试题别急着对完答案就完事花半小时在草稿纸上列一个“我错了什么知识板块”的清单然后针对性地找同类型题目集中刷几道。这套方法我从校招一直用到跳槽每次都很管用。你现在拿这套题目练手按这个流程来笔试能力应该会有很明显的提升。
返回列表