我不会写链表

也许很多人会觉得这说出来很丢人:一个程序员连链表都不会写。

是的,现在的我不会写链表。大学的我还会这些链表、树、栈等数据结构,以及各种排序算法。但是工作几年后,这些内部实现早已忘光。现在我只会使用这些数据结构和算法。

为什么会忘光

有以下几个原因。

  1. 实际工作环境中,我们不是离线编程的。随时都能上网查资料。
    这也是现在的我不会的原因,因为这些答案我很快就能查到,花点时间就能拿来用甚至改造。

  2. 我记忆的是解决问题的方法和元方法,而不是刷题记忆问题和答案。
    因为细节会变,答案也就随之变了。在技术以及互联网行业,变化是常态。
    我知道解决问题的正确方向和思路,就能沿着方向找到正确答案。无需记住每个问题和每个答案。

  3. 在我 9 年的职业生涯中从来不需要手写这些基础结构和算法。
    我的工作内容是前端、后端业务开发,以及部署、运维工作。涉及的技术栈有 HTML/CSS/JS/TS/React/Webpack/NodeJS/Go/Python/Shell/Docker/K8S/Linux 系统运维操作/网络配置、管理、排障。这些工作从来没有需要我手写基础库。
    比起算法能力,工作更需要的是工程能力,快速学习能力,以及解决问题的能力。现实来看,大部分技术都是要现学现用的,因为技术在不断迭代升级。

  4. 标准库很成熟,这是工业化生产的必然要求和结果。
    你无需自己手写链表、树等数据结构,但你需要知道如何使用它,以及在哪里使用它。有些算法很复杂,比如安全领域,你来写加密解密算法,别人未必敢用。

  5. 过早优化是万恶之源 (Premature optimization is the root of all evil)。
    如果我们放着成熟的标准库不用转而自己去优化算法和数据结构。你先问问你的老板答不答应给你时间折腾吧。

  6. AI 辅助编程很给力。AI 可以帮你写代码,甚至能帮你写单元测试。
    目前我试过用 ChatGPT 3.5 写各种数据结构和排序算法,以及其单元测试。数据结构看起来不错,能直接用。但排序算法还是有些错误,没法不修改就跑通测试。

什么时候需要手写数据结构和算法

我简单整理了几个场景:

  1. 当算法和数据结构成为性能瓶颈时,需要优化。
  2. 必须要修改底层实现才能完成需求。
  3. 面试。

对于 1、2 场景,具体比如研发 AI 算法、系统调度算法、数据库引擎等场景。
场景 3 是现实中最普遍的。下面主要聊聊面试。

为什么面试要考基础

刚毕业的学生没有多少工作经验,而他们最大的经验是学校课本上教的那些,上课、考试、毕业论文都在锻炼他们的基础能力。所以面校招生主要是数据结构和算法。其次是竞赛和项目经验。

对于社招,他们的主要精力用于工作项目中。所以面试主要考察的是他的工作经历和个人能力与应聘岗位是否契合。其次是基础能力是否过关。

一句话总结:校招主要看基础,社招主要看经验。

为什么我不愿意刷题

  1. 刷题对我的唯一好处是能够让我不至于因为笔试题没过被刷。
  2. 刷题要耗费我大量的时间。
  3. 面完试后这些题还是会忘光。

对于面试官来说,一次面试只需要出 2~5 道题即可。对于面试者来说,要准备的题是巨量的。

笔试题的题型和题量可以参考力扣 (LeetCode)。我统计了力扣的题库
截至 2023 年 4 月 6 日,一共有数组 1522 题,字符串 681 题,哈希表 532 题,动态规划 498 题,数学 487 题,排序 347 题,深度优先搜索 325 题,贪心 312 题,广度优先搜索 262 题,树 259 题,二分查找 250 题,矩阵 220 题,数据库 220 题,二叉树 216 题,双指针 205 题,位运算 194 题,栈 163 题,堆(优先队列)157 题,设计 149 题,图 144 题,前缀和 128 题,模拟 126 题,回溯 120 题,计数 109 题,链表 102 题,滑动窗口 96 题,并查集 84 题,递归 63 题,分治 57 题,单调栈 56 题,有序集合 57 题,二叉搜索树 56 题,字典树 55 题,枚举 51 题,队列 48 题,状态压缩 43 题,记忆化搜索 41 题,几何 38 题,线段树 38 题,拓扑排序 37 题,数论 34 题,树状数组 29 题,哈希函数 27 题,博弈 25 题,数据流 24 题,组合数学 22 题,字符串匹配 21 题,最短路 21 题,滚动哈希 19 题,交互 18 题,脑筋急转弯 15 题,随机化 14 题,归并排序 14 题,单调队列 13 题,双向链表 12 题,快速选择 11 题,迭代器 10 题,概率与统计 9 题,多线程 9 题,桶排序 8 题,后缀数组 6 题,计数排序 6 题,最小生成树 5 题,扫描线 4 题,Shell 4 题,水塘抽样 4 题,欧拉回路 3 题,基数排序 3 题,强连通分量 2 题,双连通分量 2 题,拒绝采样 2 题。

刷题需要多长时间

现在做几个合理的假设。

假设面试者知道面试官会从力扣题库里选题,但不知道他的选题范围。那么最靠谱的就是把这题库全刷一遍。

我刷题的最简流程是:

  1. 分析题目 (假设要花费 1 分钟)。
  2. 自己写一遍答案 (假设要花费 10 分钟)。
  3. 对比并理解标准答案 (假设要花费 2 分钟)。
    • 如果跟答案相差不多就直接过。
    • 如果相差比较大就需要学习理解 (假设要花费 10 分钟)。
  4. 通常一道题会有很多种解法,我们需要写多个解法,对比最优的空间复杂度和时间复杂度。假设每多一种解法就要额外花费 10 分钟。

假设题库中我能一遍就答对的题占 30%,多解法的题占题库的 40%,每题的平均解法有 2 种。那么我刷完一题的平均时间是 1+10+2 + 10*0.7 + (2-1)*10*0.4 = 24 分钟 = 0.4 小时

假设面试官只面试基础数据结构,那么要刷的题有:数组+哈希表+树+二叉树+二叉搜索树+字典树+栈+堆+图+链表+队列+单调队列+双向链表 = 3279 题
刷题需要的时间:3279 题 * 0.4 小时/题 = 1311.6 小时。这意味着不间断连续学习 54 天 15 小时 36 分钟。

假设面试官只面试基础算法,那么要刷的题有:字符串+数学+排序+深度优先搜索+广度优先搜索+二分查找+双指针+位运算+前缀和+回溯+计数+递归+分治+枚举+哈希函数+字符串匹配+最短路+归并排序 = 3359 题
刷题需要的时间:3359 题 * 0.4 小时/题 = 1343.6 小时。这意味着不间断连续学习 55 天 23 小时 36 分钟。

假设面试官只面试相对高阶一点的算法,那么要刷的题有:动态规划+贪心+滑动窗口+并查集+状态压缩+记忆化搜索+拓扑排序+博弈+数据流+组合数学+滚动哈希 = 1201 题
刷题需要的时间:1201 题 * 0.4 小时/题 = 479.6 小时。这意味着不间断连续学习 20 天 24 分钟。

按以上假设,如果我只准备基础的数据结构和算法,需要至少不间断连续学习 110 天 15 小时 12 分钟。更何况我不可能不吃不喝不睡全在刷题。假设我平均每天花 8 小时刷题,那么我需要 331.9 天才能刷完基础题库!

我对刷题的态度

辛辛苦苦花了大把时间和精力去研究和记忆这些题目和答案,只是为了通过面试。在你通过面试后,这些知识就极少用到或者再也不会用到(注意,这里的“用到”是指手写数据结构或算法,而不是使用它们)。
这就是我厌恶应试教育与背八股文的原因。刷题对你自己的唯一好处是能够让你不至于因为笔试题没过被刷。可是对团队,对公司有什么好处?算一下投入回报率 (ROI),值得吗?

面试官可能会认为没有刷题是态度问题。我能够理解面试官的逻辑。不过每个人的态度与选择都有其原因。
比如我,我希望不要“面试造火箭,工作拧螺丝”。希望所学的东西都能用在工作中。人生苦短,少浪费时间,多做有价值有意义的事情。
我的态度也已经写在了我的简历里:「算法零分,没刷题不背八股文。因为算法不是我的核心竞争力,职业生涯中除了面试很少需要亲自手写算法。如果工作需要,我会现学现用。」

我建议面试官以及管理者不要轻易地以己度人。很多情况下,需要多问别人为什么,或许能得到不一样的观点。

如何考察面试者的能力

如果不面数据结构和算法的笔试题,那么要如何考察面试者的能力?可以参考我在 2018 年写的文章《如何面试他人》。
顺便引用其中的一段话。

对于面试官来说,期望的是了解候选人真正的能力是否满足岗位需求和团队的期待。

如果这个岗位招聘的算法工程师,那么面试算法题是必要的。
如果是与算法和数据结构内部实现没什么要求的岗位,那么,
若做出这些笔试题,是否代表着候选人能够独立完成业务目标,足以满足岗位需求?
若做不出这些笔试题,是否代表着候选人就无法独立完成业务目标,足以满足岗位需求?

最后

看到一张挺有趣的梗图。分享给大家。


许可协议
未经授权,不得全文转载。转载前请先阅读本站版权声明