ARTICLE DETAIL

资讯详情

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

小红书iOS岗秋招笔试复盘:考点分析与算法实战

小红书iOS岗秋招笔试复盘:考点分析与算法实战 2023年秋招的小红书iOS开发岗我正好赶上了第三批笔试。写这篇复盘不是说题目有多难而是这批笔试的考察风格、题目范围和时间节奏跟很多同学在牛客上刷到的前两批内容有明显差异。如果你正在准备互联网大厂或小红书的iOS岗位这篇复盘应该能帮你少走不少弯路。整个笔试时长120分钟平台是牛客网的在线笔试系统支持C、Java、Python、Swift这些主流语言。第一部分是单选题和多选题混在一起大概20道覆盖网络、操作系统、数据库和iOS特性第二部分是3道算法编程题难度递进。我投的是上海那边的客户端团队第三批发放笔试通知的时间晚于前两批同期投递的同学里过了简历筛的人数量明显比前两批少。这意味着第三批的笔试通过率会更残酷面试官手上的招聘名额大概率已经所剩不多笔试成绩基本决定你能不能拿到面邀。1. 第三批笔试的特殊处境投得越晚考察越偏实战先说说第三批这三个字意味着什么。秋招的笔试批次一般不是官方刻意划分的而是根据简历投递时间自动滚动触发。小红书2023年秋招iOS开发岗的简历收集从八月中旬开始每两周左右集中发一批笔试邀请。前两批还在九月上旬和中旬hc相对充足笔试通过率会宽松一些到了第三批基本是九月底到十月上旬这个时候很多同学手里已经拿了其他公司的offer但小红书的客户端岗位竞争依然白热化因为小红书的iOS端技术氛围在业内口碑不错尤其在音视频、图像处理、动态化这些方向上积累很深。你可能会问第三批笔试会不会比前两批更难我的体感是题目难度没有明显攀升但对工程实践的考察权重变大了。前两批网上的面经帖总结的考点集中在基础数据结构和简单动态规划而第三批我在考场上明显感觉到概念题占比更高、场景题更贴近真实业务。比如有几道题是给一段iOS代码让你判断会不会崩溃、会不会循环引用、会不会导致UI卡顿。这种题靠临时刷LeetCode是刷不出来的必须真正写过iOS项目、踩过内存和渲染的坑才能一眼看出问题在哪。第三批的另一个特点是面试官会在后续环节追问笔试中的解题思路。小红书的技术面通常不止一轮一二面都会挂靠笔试中的某道题来深挖问你为什么这么设计你的方案在内存上有没有优化空间。所以这批笔试不能只求AC通过所有测试用例还要保证每道题你都能讲清楚设计思路这也是为什么我建议大家考完后立刻复盘、整理现场代码而不是交卷就完事。提示第三批笔试通常在国庆前后这个时间点别只盯着小红书一家。很多公司的笔试都是滚动发放的建议建一个信息表记录投递日期、笔试日期、笔试链接有效期限防止漏考。小红书的笔试通知邮件有时会被归入垃圾箱记得在邮件搜索框直接搜笔试。2. 客观题考点复盘iOS专属与通用基础七三开整份试卷大约20道客观题我按照记忆范围把考点分成三类如果你准备2024年之后的秋招这三块基本是必须覆盖的。2.1 计算机基础部分网络和并发是重头网络相关题目考了三次TCP三次握手状态变化、HTTP/1.1与HTTP/2的多路复用区别、HTTPS证书校验流程。TCP握手题不是直接问你第一次握手发什么而是给出一张连接状态迁移图让你判断某个状态发生在哪个阶段。HTTP/2的题目要求选出正确描述很多选项跟队头阻塞有关这里我差点选错——HTTP/1.1的队头阻塞是应用层问题HTTP/2虽然通过多路复用缓解了它但TCP层的队头阻塞依旧存在因为TCP必须保证有序传输。操作系统层面考了进程和线程的区别、死锁的四个必要条件、虚拟内存缺页中断。这些题目难度不高但有个坑是并发题和iOS的GCD混在一起考。比如问以下哪些方式会创建新线程选项里同时出现了DispatchQueue.main.async和DispatchQueue.global().async如果不熟悉GCD很容易把主队列当成新线程。正确的记忆方式是主队列对应的主线程只有一个全局队列背后才是系统线程池。2.2 iOS内存管理从ARC到自动释放池iOS专属考点考了Autoreleasepool在RunLoop中的释放时机、__weak修饰符的作用、循环引用的判断、Block对捕获变量的处理方式。其中有一道题问的是__weak和__unsafe_unretained的区别。这两者都不会增加引用计数区别在于对象释放后__weak指针自动置nil而__unsafe_unretained变成野指针。这道题只要真正在项目里用__weak修饰过代理属性基本不会选错。Block是重点中的重点。题目给了以下代码NSMutableArray *array [NSMutableArray array]; void (^block)(void) ^{ [array addObject:1]; }; self.block block;问这段代码是否形成循环引用。我当时选的是会形成循环引用原因是self持有blockblock内部捕获了外部的array变量而array是self的属性时block会强引用self形成self - block - self的环。如果只是__block NSMutableArray *array这种局部变量则要看有没有被self持有。这道题的细节在于理解block捕获的是变量本身还是变量指向的对象捕获局部基本类型变量值拷贝到block内部不增加引用计数捕获对象类型局部变量强引用该对象除非用__weak或__unsafe_unretained修饰捕获__block修饰的变量包装成结构体block内部可以修改变量值但同时也会强引用包装对象2.3 iOS UIKit与系统框架不再只考背概念今年的考题里UIKit部分明显比重加大。有一道是UIStackView的排列行为在垂直排列的UIStackView中给其中一个子视图设置translatesAutoresizingMaskIntoConstraints NO会怎样选项很刁钻正确答案是会导致约束异常或崩溃因为UIStackView内部的子视图约束由它自己管理手动设置这个属性会干扰它的自动约束生成逻辑。这种坑只有真正用UIStackView做过复杂布局的人才知道。还有一道关于App启动流程didFinishLaunchingWithOptions到第一帧渲染之间系统做了哪些事情。这道题直接对应优化启动时间的场景面试官后续还问了如何统计启动耗时、如何减少主线程工作。如果你做过启动优化的埋点统计答起来会很顺。蓝牙相关的考点让我比较意外。有一道多选题问的是CBCentralManager中系统级蓝牙状态.poweredOff和应用级蓝牙权限被拒绝时回调有什么区别、能否在同一个回调里区分。这确实是从真机调试中提炼出来的问题。真实开发中用户可能既在系统设置里关闭蓝牙又单独关闭了App的蓝牙权限两个状态在回调里长得不一样需要在UI层区分展示不同的引导文案。这个知识点在普通iOS面试题总结里几乎看不到但小红书是做社区App的图片/视频上传、附近的人、蓝牙设备交互这些功能都有涉及所以他们考察这个方向并不意外。注意准备小红书这种业务型App的iOS岗别只刷LeetCode和背八股建议自己做一个小型完整App涉及网络层封装、图片加载缓存、列表流畅度优化、推送处理这几个模块笔试里很多看似冷门的知识点做完这些模块后会自然形成肌肉记忆。3. 算法题手撕过程从暴力到AC的完整推演小红书笔试的三道算法题在牛客网题库里都不是原题但思路并不新颖。我拿到题之后的感受是不考偏题怪题但每道题都需要你认真分析边界条件暴力解法大概率只能过部分用例。3.1 第一题字符串处理与滑动窗口第一题大概是这样的给定一个只含小写字母的字符串请找出最长连续子串要求该子串内任意两个字符的出现次数之差不超过k。字符串长度在10^5级别。一上来我想到的是暴力枚举所有子串对每个子串统计字母频率并判断差值是否超过k复杂度O(n²)显然会超时。进一步思考这类连续子串 字符种类 频率限制的问题通常用滑动窗口维护窗口内每种字符的出现次数并动态记录当前窗口的最大频率和最小频率。窗口右边界不断右移每次加入一个新字符后更新该字符频率。为了判断窗口是否合法需要知道窗口内出现次数最大的字符频率和最小的字符频率这个差值如果大于k就不断收缩左边界直到差值重新小于等于k。问题在于收缩左边界和右移右边界的过程中如何快速维护最大/最小频率暴力更新窗口内所有字符频率是O(26)在字符集大小恒定为26的情况下O(26n)也等于O(n)所以完全可以直接遍历26个字母找最大最小频率不需要引入堆或有序结构。int longestSubstring(string s, int k) { int n s.size(); vectorint cnt(26, 0); int left 0, ans 0; for (int right 0; right n; right) { cnt[s[right] - a]; while (true) { int mx 0, mn INT_MAX; for (int i 0; i 26; i) { if (cnt[i] 0) { mx max(mx, cnt[i]); mn min(mn, cnt[i]); } } if (mx - mn k) break; cnt[s[left] - a]--; left; } ans max(ans, right - left 1); } return ans; }这道题我AC了但事后复盘发现了一个可以优化的点每次判断窗口是否合法都扫描26个字母虽然理论上是O(n)但在用例特别多且字符串特别长时跑满26倍常数仍然有点吃力。可以考虑维护两个有序容器或者用哈希表记录频率分布不过这题的时间限制比较宽容O(26n)完全能过。关键心得是滑动窗口不是简单右移左移而要先想清楚窗口维护的目标值是什么。这里的核心是窗口内最大频率和最小频率的差值那么右边界加进来的字符会影响最大值也可能影响最小值左边界移除的字符同样如此。只要你能保证每次判断的时间是常数级别或字符集级别的常数这个题就能稳过。3.2 第二题动态规划与状态设计第二题考了一个二维网格从左上角到右下角的路径规划问题但加了一个限制每个格子有权值经过一个格子会获得对应分数不能重复经过已经走过的格子求最大得分。这个限制意味着不能直接使用普通DP因为普通DP假设每个格子最多经过一次而正向DP会默认路径是单调向右或向下的如果允许来回走就需要考虑状态压缩之类的技巧。我的第一版做法是深度优先搜索从起点开始把当前经过的格子标记为已访问递归遍历上下左右四个方向回溯时恢复状态。这个解法能保证正确性但复杂度是指数级的在网格稍大时完全不可行。进一步分析后发现这道题有一个非常关键的限制条件移动方向只能向右或向下且走过的格子不能再走。实际上很多笔试题目都会给只能向右或向下移动这样的条件只是出题人把它藏在了描述里我一开始没仔细读题误以为可以上下左右自由移动导致第一版DFS完全跑不过用例。一旦限定只能向右或向下状态就非常简单了到达某个格子时经过的路径就是固定的不会重复直接二维DP即可int maxScore(vectorvectorint grid) { int m grid.size(), n grid[0].size(); vectorvectorlong long dp(m, vectorlong long(n, 0)); dp[0][0] grid[0][0]; for (int i 0; i m; i) { for (int j 0; j n; j) { if (i 0) dp[i][j] max(dp[i][j], dp[i - 1][j] grid[i][j]); if (j 0) dp[i][j] max(dp[i][j], dp[i][j - 1] grid[i][j]); } } return dp[m - 1][n - 1]; }这道题给我的教训是笔试审题比做题更关键。我看漏了只能向右或向下这句话白白浪费了十几分钟。如果是面试现场遇到这种问题一定要先把题读三遍甚至把限制条件用笔抄在草稿纸上防止自己脑补出更困难的问题。3.3 第三题拓扑排序与贪心的结合第三题是关于任务调度的有n个任务每个任务有不同的执行时间和依赖关系某些任务必须等另一些任务完成后才能开始。只有一台机器完成所有任务的最短时间是多少。这个题本质上是最长路径问题对于一条任务链A - B - C完成时间为time[A] time[B] time[C]。在多条依赖链并行的情况下总时间取决于最长的链。所以解法是拓扑排序维护每个任务点的最长完成时间int minimumTime(vectorint time, vectorvectorint relations) { int n time.size(); vectorvectorint graph(n); vectorint indegree(n, 0); vectorint dist(n, 0); queueint q; for (auto e : relations) { int u e[0] - 1, v e[1] - 1; graph[u].push_back(v); indegree[v]; } for (int i 0; i n; i) { dist[i] time[i]; if (indegree[i] 0) q.push(i); } int ans 0; while (!q.empty()) { int u q.front(); q.pop(); ans max(ans, dist[u]); for (int v : graph[u]) { dist[v] max(dist[v], dist[u] time[v]); if (--indegree[v] 0) q.push(v); } } return ans; }这道题我AC了AC之后感觉很顺。核心是意识到拓扑排序中dist[v]的更新方式它表示从某个入度为0的任务开始到任务v的最长路径总耗时每当一个前驱任务u完成就尝试用dist[u] time[v]去更新dist[v]取最大值。这样所有依赖关系处理完ans就是所有任务中的最大dist值。经验第三题很多笔试都会出这个知识点。建议把拓扑排序的模板刻在脑子里同时牢记求最短时间求最长路径这个转化。这种题一旦想到了模板代码写起来非常快。4. 在线笔试环境的坑与时间分配差点在IDE上翻车第三批笔试有个很现实的体验问题在线IDE和本地Xcode的差异太致命了。Xcode有代码补全、实时报错、头文件自动引入而牛客网的在线编辑器几乎没有任何智能提示Objective-C的代码写起来异常痛苦。我第一题本来准备用Swift写但看到在线编辑器里Swift的Foundation头文件支持不太完整果断换成了C。这个决策后来被证明是正确的——Swift里数组的边界检查在在线环境可能不会给出明确报错而是直接崩溃你根本不知道哪里越界了。建议在笔试前花20分钟熟悉牛客网的在线编辑器。至少在正式考前几天用它的模拟笔试功能跑一两道题搞清楚几个问题代码提交是手动点运行还是自动保存输入输出是从标准输入读还是从形参传入多个测试用例是一次性跑完还是逐个击破能否本地编译调试后再粘贴到编辑器时间分配上我的策略是0-15分钟做所有客观题不会的先标记跳过不要恋战15-75分钟集中做三道算法题从第一题开始确保前两题AC后再攻第三题75-90分钟回看被标记的客观题结合已经写过的代码逻辑唤起记忆90-120分钟检查代码的边界情况补充注释在草稿纸上写下每道题的思路面试可能会问这套时间分配执行下来我最后还剩15分钟检查时间。其实客观题部分我在30分钟内就完成了因为很多题答案是靠实践积累的不需要现场推理真正耗时间的是第三题我一开始没反应过来是最长路径问题先去套了DP的壳写了十几分钟发现不对转拓扑排序后代码量不大但想通的时间很费。提示如果你在笔试过程中遇到平台崩溃、提交超时、代码无法编译等问题一定不要慌张地反复重试。先截图保存然后联系平台客服。秋招笔试期间牛客网的系统出小问题的概率不低但通常不会影响最终成绩重试有时会触发数据上报重复反而把你的提交记录搞乱。我当时就遇到过一次代码提交后返回网络错误刷新后发现其实已经提交成功。5. 这套笔试给后续秋招的人哪些参考方向按题型反推准备策略考完复盘完这套题我能明显感觉到小红书iOS开发岗的笔试风格指向一个方向业务导向、工程能力优先。他们不指望你现场发明新算法但要求你写出来的代码经得起推敲同时对iOS底层的理解不能停留在背书层面。5.1 三道算法题反映的刷题侧重点从题目分布看三道题分别是滑动窗口、二维DP、拓扑排序都是LeetCode中等偏上难度的常见题型。如果你在准备小红书或其他大厂的iOS岗建议按这个优先级刷题高频滑动窗口、双指针、HashMap计数、DFS/BFS、拓扑排序中频区间DP、状态压缩DP出现概率低但遇到容易暴击、并查集、前缀和低频线段树、树状数组、网络流、计算几何牛客和小红书历年笔试的大数据统计都能验证这个频率分布。题库刷个300题左右基本能覆盖大多数笔试场景但一定要保证每道题都理解到位而不是背代码。因为面试官会让你讲思路、改边界条件。5.2 iOS客观题和面试的无缝衔接刚才说的蓝牙状态区分、UIStackView陷阱、启动优化这道题其实都指向面试中会深挖的方向。我后来在二面时被问到如果你是小红书的iOS开发如何设计图片上传模块的并发控制这个问题跟我笔试中遇到的GCD和并发题目完全吻合。小红书的内容形态以图文为主图片上传、视频处理、消息推送是客户端团队的核心业务所以你在这个方向上的积累会直接决定面试官对你的评价。具体来说准备iOS岗位时以下的工程知识点必须亲手做一遍图片缓存实现一个支持二级缓存内存磁盘的图片加载器处理图片解码、缩略图、取消加载列表流畅度用 Instruments 检测滑动时的掉帧问题理解cellForRowAtIndexPath中的耗时操作如何优化网络层封装基于NSURLSession封装一个支持请求拦截、统一鉴权、重试机制的网络组件异常捕获掌握NSSetUncaughtExceptionHandler和signal处理机制理解崩溃日志的上报链路动态化方案了解Hybrid、React Native、Flutter在iOS端的基本原理以及它们和原生渲染的分工这些不是靠背八股能掌握的需要你在项目里踩过坑。以图片加载为例你可能会遇到imageNamed:和imageWithContentsOfFile:加载方式对内存的占用差异可能会遇到在主线程解码大图导致卡顿这些都是真实业务中高频出现的问题也是小米、小红书这类内容型公司面试官非常乐意追问的素材。5.3 考后24小时内的复盘动作考完试别急着去对答案先做三件事把自己在考场上的代码复制到本地Xcode里跑一遍看是否真的AC记录每个题的耗时对每道题写一段解法思路模拟面试讲解的口吻说一遍录下来听有没有逻辑漏洞把客观题中不确定的知识点都查一遍资料整理进自己的知识库形成错题集我的错题集里专门建了一个笔试易错概念的分类每道题记录题目描述、错误原因、正确解释、关联工程场景。之后面试被问到相关知识点时直接翻这个错题集就能快速回忆起来比翻书效率高得多。注意秋招期间笔试密集有些公司笔试题目不能外泄所以别在网上公开回忆真题的原文。正确做法是抽象出考点用自己的话重新组织题目逻辑并总结知识点既能保护自己也是对自己知识内化的检验。6. 写在最后的个人经验笔试考的是可被深挖的能力三批笔试走完我最大的体感是小红书这类公司的笔试重点不在你写出一个能跑的答案而在于你的答案是否有足够的延展空间供后续面试深挖。滑动窗口那题做完后面试官问我如果字符集不是26而是10^5你还能O(n)解吗这就是在考察你对算法本质的理解而不是背模板。所以我的建议是从准备阶段就要带着这个知识点面试官会怎么追问的心态去学。写Block的时候问自己循环引用在什么场景下会出现用__weak就一定安全吗为什么写图片缓存的时候问自己内存缓存用NSCache和NSMutableDictionary有什么本质区别NSCache的自动清理机制在系统内存警告时会不会立即释放这些追问的深度直接决定你面试时是流畅应答还是卡壳。最后说一个大家容易忽略的小细节笔试前把电脑通知关掉把手机调成勿扰模式。我第三题拓扑排序写到一半微信突然弹了一个群消息提醒直接打断思路差点导致队列的入队操作重复执行。这种低级失误一旦出现真的很伤士气。如果你也在准备iOS客户端岗位希望这篇复盘能帮你更清楚后面该怎么使劲。第三批笔试只是秋招的一个节点过了就安心准备面试没过也别气馁很多公司的客户端岗位是持续滚动招聘的。保持复盘习惯下一个笔试一定能更稳。
返回列表