51天算法学习笔记:用“笨办法”打通算法学习路线
1. 从“更弱智”说起为什么我建议你用笨办法学算法先交代一下背景。这是我连续记录算法学习笔记的第51天标题里“更弱智”三个字不是自谦是我反复试错后总结出来的方法论把自己当成一个“弱智”去学算法反而学得最快。为什么这么说我见过太多人打开《算法导论》翻到红黑树那一章硬啃两小时看懂了旋转的每一步合上书第二天全忘光。问题不在智商在于用看小说的方式去学算法——只满足于“看懂”从不逼自己“做出来”。我给自己的规矩很简单任何算法必须做到能用大白话讲清楚它干了什么能徒手写出核心代码能说出它适合什么场景、不适合什么场景。如果三件事里有一件做不到就当自己没学会回家重学。这个过程很笨、很慢、很“弱智”但效果出奇地好。过去51天我按一个相对完整的图谱过了一遍从最基本的排序、查找到字符串匹配、图论、动态规划再到机器学习、深度学习里常用的优化算法、聚类算法、回归算法后面又补了PID控制、CRC校验、粒子群优化这类工程味道很浓的算法。这篇文章不是要重讲某几个算法——那是教科书和视频课的事——我想聊的是从day1走到day51哪些算法之间的脉络是相通的哪些坑是完全可以绕开的以及那个“更弱智”的学习框架到底怎么落地。不管你是在校学生、准备面试的求职者还是工作中被迫接触算法的开发这套思路应该都能派上用场。文章会比较长我尽量按学习顺序而不是目录顺序来写因为后者是教科书逻辑前者才是人脑真正记住知识的逻辑。2. 先把整个算法地图摊开51天我到底学了什么2.1 算法不是一堆孤立的技巧而是四类问题的解法集合很多人学算法最大的误区是把它当成“一道一道的题”。今天刷一道两数之和明天刷一道反转链表刷完200题遇到新题还是懵。我学到day20左右才意识到问题出在没有建立问题类型的概念。冷静下来把所有算法归归类会发现整个算法世界其实就四件事让数据有秩序排序算法、堆、二叉搜索树、哈希表本质都是为了让数据变得“好找”。这一类是地基面试里80%的题绕不开它们。在结构里找路图、树、深度优先、广度优先、拓扑排序、最短路径Dijkstra、Floyd、最小生成树Prim、Kruskal解决的是“怎么从一个点到另一个点”的问题。A*算法、粒子群这些寻优策略本质上也是找路只是路径空间变成了抽象的参数空间。用穷举干掉不确定性动态规划、回溯、贪心、剪枝。核心思路是把大问题拆成重叠子问题或者用暴力搜索加合理剪枝逼近最优解。从数据里学规律线性回归、随机森林、聚类、强化学习、深度学习优化器这些是机器学习/深度学习算法解决的是“从样本中归纳规律”的问题。想通这个分类后我后面30天的学习节奏明显变快了因为很多算法在“问题本质”上是同一个东西。比如KMP算法和状态机比如PID算法和PID调节器再比如匈牙利算法和二分图匹配它们都不是孤立的知识点。2.2 day1到day51的路线图从小白到有条不紊的摸索路径我的实际学习顺序是这样的你可以参考但没必要完全照抄第一阶段day1-10基础数据结构 排序数组、链表、栈、队列、哈希表然后是冒泡、选择、插入、归并、快排、堆排序。这一阶段的目标不是背代码而是理解“比较和交换”为什么能排好序理解时间复杂度的意义。第二阶段day11-20树、图、搜索二叉树、平衡树、二叉堆、图的邻接表表示DFS/BFS拓扑排序、Dijkstra、Floyd。这一阶段会有很强的“顿悟感”因为你发现很多看起来花里胡哨的算法背后就是“排队遍历”和“贪心选最小”。第三阶段day21-30字符串 动态规划 贪心 回溯KMP、Trie树、LCS、背包问题、最长递增子序列、子集枚举、剪枝。这一阶段最容易劝退因为动态规划刚开始就是反直觉的你必须接受“先算小、再算大”的思路。第四阶段day31-40工程类算法 数学类算法MD5、CRC校验、PID控制、快速幂、矩阵快速幂、Tarjan求强连通分量、匈牙利算法。学到这你会发现很多工业软件里跑得飞快的算法基础也就是你前30天学的那些东西。第五阶段day41-51机器学习 优化算法线性回归、逻辑回归、决策树、随机森林、K-Means聚类、梯度下降、Adam优化器、强化学习的基本框架Q-Learning、策略梯度、遗传算法、粒子群算法、模拟退火。这块单独拎出来说一句真正的算法工程师和普通开发的分水岭就在这里你得理解最优化的思想。这条路线不算最优但它是真实可行的。如果你时间有限至少前三个阶段要扎实后面两个阶段可以按需补充。2.3 “更弱智”学习法的核心费曼技巧 手写实现 场景绑定现在说方法。我用的框架其实就是“费曼技巧”在算法领域的变形加上两个硬性要求第一每个算法要能用讲给小学生听的语气说出来。不是背定义而是真的理解。比如什么是快速排序我会说“我选一个中间人比它小的站左边比它大的站右边然后两边各自再找中间人重复到只剩一个人。”这就算过关。如果你发现自己必须用到“分治”“递归”这种词才能解释说明还没吃透。第二必须不看任何资料手写实现。这一条会暴露一切“以为自己会了”的幻觉。我统计过真正能做到“看懂——合上书写出来——跑通——再默写一遍”的算法占比不到六成。剩下的四成比如KMP的next数组、Tarjan的low值更新、匈牙利算法的增广路径都需要反复拆解。第三给每个算法绑定至少一个“真实场景”。不是为了面试造轮子而是为了在脑子里留下锚点。冒泡排序像气泡往上冒堆排序像排行榜实时更新KMP像在书里跳着找关键词匹配失败时知道跳过前面的已知匹配部分PID像空调温度调节器——温度高了就降功率低了就升偏差大就猛调偏差小就微调。这条“三件套”路线我用了51天真实感受是前期慢中期突然加速度后期能很快抄底新算法——因为很多新算法本质上是你学过的旧算法的变体。3. 手把手拆几个“看起来很唬人”的算法3.1 归并排序和快速排序理解分治思想的第一次顿悟先谈排序。很多人觉得排序简单但排序是算法思想的微缩宇宙值得反复琢磨。拿归并排序讲明白“分治”。它的思路是把数组从中间切成两半左半边自己排右半边自己排然后合并两个有序序列。这里最隐蔽、最关键的操作是最后一步“合并”——它需要额外的临时数组这就是归并排序空间复杂度O(n)的原因。时间复杂度是稳定的O(n log n)意味着不管你给的数据乱成什么样性能不波动。归并排序的时间复杂度推导值得一提每一层递归所有元素总共被“看”一遍复杂度为O(n)递归深度为log n层总复杂度O(n log n)。这是最好的例子。快速排序就“野”一点它的核心是选一个基准pivot把小于基准的放左边大的放右边。平均情况O(n log n)但最坏情况O(n^2)——当你每次选的基准都恰好是最大或最小元素的时候比如对一个已经有序的数组用固定位置选基准就会退化。所以工业级实现会做“三数取中”或者随机选基准就是为了防这种退化和可能的对抗攻击。快排不用额外数组所以平均空间是O(log n)优于归并排序。这两个排序放在一起对比最值得学到的是同样解决一个问题权衡维度可以完全不同。归并排序稳定、可控、但占内存快排平均快、省内存但运气差的角落。没有“最好的算法”只有“最合适的算法”。3.2 KMP算法从“暴力匹配”到“跳着查”的思维跃迁字符串匹配是面试高频点但很多人一听到KMP就头皮发麻。我花了两天时间才真正通透了它方法很“弱智”手工模拟一遍全过程把每一步的指针移动都写下来。暴力匹配的做法是模式串从文本串第一位开始试匹配失败模式串整体后移一位重新从头比较。问题在于一句“重新从头比较”可能浪费了已经比对过的信息。KMP的核心思想是匹配失败时模式串不要只后移一格而是利用“部分匹配表”next数组直接跳过那些不可能是匹配位置的地方。举例来说模式串“ABCDABD”在匹配到“ABCDAB”时失败此时末尾的“AB”已经在文本串里出现过了我们可以利用这一点让模式串跳到“AB”开头的位置开始下一次比较而不是从头再来。next数组的构建是KMP的难点很多人死在递归推导上。我的理解方式是——next[i]表示模式串前i个字符组成的子串中最长相等的前缀和后缀的长度不包含自身。比如“ABCDAB”最长相等前缀后缀是“AB”长度2所以当第6个字符D匹配失败时我们可以直接把前缀“AB”挪到后缀“AB”的位置上去。这样文本串的指针永远不回退模式串指针回退到next数组指定的位置总复杂度O(nm)。我强烈建议你写个例子用笔在纸上模拟比如用文本串: BBC ABCDAB ABCDABCDABDE和模式串: ABCDABD把i和j每一步的动作列出来10分钟就能通。KMP真正教你的不是代码而是“如何从已发生的失败中提取有效信息”这个思维模型。3.3 动态规划为什么先算小问题能算出大问题动态规划是我学得最痛苦、也受益最大的一块。它和内功心法很像乍一看什么规则的没有一旦理解透了很多题都是套路。动态规划的核心讲透了就一句话大问题的最优解可以由小问题的最优解推导出来。你要做的是三件事定义状态、找状态转移方程、确定初始条件。拿斐波那契数列举例f(n) f(n-1) f(n-2)状态就是f(n)转移方程就是一个加法初始条件是f(0)0、f(1)1。看起来简单但很多人写代码时依然会用递归——如果直接递归复杂度是O(2^n)n稍微大一点就卡死而用一个一维数组或者两个变量存中间结果复杂度是O(n)。区别只在“浪费”和“复用”的差别。我把动态规划常见的题型归了个类一维DP爬楼梯、斐波那契、打家劫舍、最长递增子序列LIS二维DP最长公共子序列LCS、编辑距离、矩阵路径背包问题0-1背包、完全背包、多重背包这是面试重点本质是一个决策二维表区间DP矩阵链乘法、回文子串拆解状态压缩DP旅行商问题的暴力美学我建议新手入门从“最长递增子序列”开始它很好理解而且有两种解法O(n^2) DP和O(n log n)贪心二分能让你直观感受“同样是DP优化的空间有多大”。背包问题则一定要手写一遍状态转移表的填充过程把表格画出来比看十遍代码都管用。用“弱智”的标准说动态规划就是你从小到大地填一张表每个格子都在回答“如果只有这些元素最优解是多少”。最后你需要的答案往往就在表格的右下角。3.4 贪心、回溯、剪枝优化里的三兄弟讲完了DP顺带把它表亲的贪心、回溯一起说了吧。它们的共同点都是处理“选择”问题但策略不同。贪心算法在每一步都选当前看起来最优的选择期望全局最优。它最迷人的地方是只要贪心策略是对的代码往往极短比如哈夫曼编码、Prim算法、Kruskal算法都是典型的贪心。但问题是“贪心策略正确”这件事需要严格证明不然就容易踩坑。我举一个反例找零钱问题里如果币值是[1, 5, 11]要找15元贪心算法会先拿11再拿4张1元总共5张但最优解是3张5元。所以贪心适合有特定数学性质的场景不能无脑套用。回溯算法是“有组织的暴力”走一步不行就退回来换条路再走直到穷尽所有可能。经典场景是八皇后、全排列、子集生成。它有一个伴生技术叫“剪枝”——在探索过程中提前判断某个分支不可能产生最优解直接砍掉。剪枝是回溯题的核心考点好的剪枝能把O(n!)的复杂度砍到可接受范围。我做过一次“数独求解器”不剪枝可能跑几十秒加上“当前行/列/宫已经出现的数字”剪枝后毫秒级解出。这个对比让我彻底记住剪枝的价值。说到剪枝捎带提一下决策树和随机森林里的剪枝——这俩全名叫“预剪枝/后剪枝”原理一样都是为了防过拟合树枝长得太细反而把噪声学进去了。算法学习有意思的地方就在这种跨界的对应关系你在数据结构里学的剪枝居然在机器学习里又碰到一遍。3.5 从Floyd到Dijkstra、A*到PID、MD5到CRC工程世界的算法速览如果说前四类算法是“内力”下面这些更像是“套路招数”但它们在实际项目里出现频率极高值得了解一下。Floyd算法最“暴力”地求解多源最短路径三重循环枚举中转点复杂度O(n^3)但是代码很短适合节点数少的图比如几百个以内。Dijkstra是单源最短路径的经典解法配合优先队列堆时间复杂度O((VE) log V)。如果你要做游戏里的寻路A算法才是主角——它在Dijkstra基础上加了启发式函数f g hg是已走路径开销h是到终点的预估开销通过这个“预估分”优先探索更可能通向终点的节点。我说个直白类比Dijkstra是“无脑地把最近的点都看一遍”A是“看一眼前方和终点大致方向先走过去再说”。这就是为什么游戏里怪物会“聪明”许多。PID算法则完全是工程世界的语言。它由比例P、积分I、微分D三个分量组成P看当前误差I累积历史误差D看误差变化趋势。调PID像是调厨师做菜的火候——P是现在咸淡差多少I是这锅菜整体偏淡还是偏咸D是盐味在变浓还是变淡。机器人底盘循线、四轴飞行器悬停、恒温箱控温全靠它。我建议你装一个简单仿真比如用Python模拟一个一阶惯性环节温控系统调三组参数观察曲线震荡、超调、稳态误差的变化这是穷任何文字描述都替代不了的一课。MD5和CRC类似是做校验的。MD5是哈希算法把任意内容计算成固定128位摘要以前用做完整性校验但因为碰撞漏洞现在不该用在安全场景了CRC则是一种循环冗余校验在通信协议比如Modbus里用来检查传输过程中有没有比特错乱。这俩算法不看原理直接按公式实现即可但你要理解它们的定位差异CRC防误码MD5当年是防篡改后者今天应该被SHA-256替代。3.6 机器学习与优化算法线性回归到随机森林梯度下降到粒子群最后一阶段是目前学起来最兴奋的因为算法开始离“应用”最近。线性回归是最简单的“从数据中学规律”的算法。它做的事情就是找一条直线y wx b让所有样本点到直线的误差平方和最小。求解方式有两种思路一种是用最小二乘法直接求解析解另一种是用梯度下降法迭代逼近。这里梯度下降是所有深度学习算法的地基必须吃透。什么叫梯度下降想象你在山上下雾了看不见远处只知道脚下哪个方向是下坡于是你沿着最陡的下坡方向迈一步反复迭代直到走进谷底。学习率步长太大容易在谷底两侧来回震荡太小则收敛极慢。这是我当年学机器学习时踩的第一个大坑调学习率调到深夜后来才理解“自适应学习率优化器”存在的意义——Adam、RMSProp这类算法会自动帮你调整每一步的步长。随机森林是“集成的力量”的典范训练很多棵决策树每棵树用样本的一个随机子集训练最后投票出结果。它比单棵决策树稳得多几乎不会过拟合到没边是工程界性价比极高的算法。K-Means聚类则是一种无监督学习给你一堆数据点不告诉你标签算法自动把它们分成K簇大致做法是先随机选K个中心然后反复迭代“归属分配 中心更新”直到中心不再变化。这个算法特别容易理解它就像你把一堆球放在桌面上来回移动三个杯子试图让每个球都离某个杯子最近。再往深走一点强化学习学习的是“决策策略”智能体在一个环境里做动作根据环境的奖励反馈调整策略。Q-Learning的核心是一个Q表每一行是状态每一列是动作表里的值代表“在这个状态下做这个动作会有多少长期收益”。它的更新公式就是著名的贝尔曼方程Q(s, a) 奖励 γ * max(Q(s′, a′))。你品一品这个公式其实就在做“动态规划”那套事——用后继状态的价值估计当前状态的价值。看到了吧第3节的动态规划和第6节的强化学习隔着十万八千里本质是同一个思想。这就是我前面说“算法不是孤立的”的绝佳证据。粒子群算法、遗传算法、模拟退火这类“元启发式优化算法”则是另一个分支——它们不依赖梯度信息而是模拟鸟群觅食、生物进化、金属退火的物理过程。粒子群算法尤其简单优美一群“粒子”在解空间里飞行每个粒子记住自己的最优位置同时群体共享全局最优位置速度更新公式同时受“自己最优”和“群体最优”牵引。我第一次跑通粒子群算法求函数最小值时看到粒子们在二维空间里“嗖嗖”地聚向最优解那种画面感极其震撼强烈建议你也试试。4. 工具选型与实践环境我踩过的坑和你应该选的路4.1 语言选择C、Python、Java到底学哪个这是个老生常谈到干瘪的话题但必须面对。我的答案很直接如果你在准备算法面试语言不重要逻辑才重要。选你最有把握、写得最顺的语言。面试官不关心你用C还是Python关心的是你能不能在白板上写出无Bug的代码。如果你想深入理解底层原理C能逼你面对指针、内存、引用和复杂度的真相。比如实现一个红黑树用Python你会觉得“还行”用C你得思考节点析构、内存泄漏、迭代器失效这一轮下来你对数据结构的理解更深入。我能坚持下来的一个重要原因就是很多算法用C手写过一遍以后再用任何语言都能很快转换。它有“一次学会处处复用”的效果。如果你重点是机器学习和数据分析Python是事实标准。numpy、pandas、scikit-learn、PyTorch生态齐全。但请注意会用sklearn调库不等于会算法我强烈建议用numpy手写一遍线性回归、K-Means和反向传播哪怕代码再丑也有意义因为“手写过”和“用过”是两种完全不同的理解和抵御面试追问的能力。4.2 可视化与调试工具让抽象概念长出肌肉工欲善其事必先利其器。有几个工具帮了我大忙我按推荐程度排序VisuAlgo一个在线算法可视化网站排序、图论、哈希表这类算法可以一步步看动画执行。我学KMP、Dijkstra、Floyd的时候全程盯着它的动画看好几遍配合自己手写代码理解速度翻倍。Python matplotlib写一个“排序算法动态可视化”脚本把冒泡、快排、归并每次交换后的数组渲染成柱状图导出GIF。看着快排三下五除二把乱序数组拍平成就感爆棚。Python tutor逐行执行Python代码实时显示变量的堆栈状态。调回溯和DP时非常有用——你能看到递归调用栈一层层进再一层层出“函数调用栈”不再是课本上的名词。LeetCode / 洛谷刷题平台我建议按“分类题单”刷不要随机刷。比如LeetCode的“动态规划”题单有几十道经典题从爬楼梯到编辑距离做一遍差不多就掌握了DP的套路。我个人的节奏是每天3道题顶多5道重在总结不追量。4.3 笔记本和卡片最“弱智”的工具反而是最强大的最后说一个最容易被忽视的工具一个实体笔记本和一堆空白卡片。我的习惯是每学一个算法在卡片正面写算法名称背面写三行话第一行大白话讲思路第二行写时间和空间复杂度第三行写这个算法的“不适场景”。这三行话逼着我把“理解”压缩成“要点”写不出来的话说明没懂。复习时我随机抽卡片看一眼名字翻过背面核对这种检索式练习比反复读笔记有效太多。51天下来我已经积累了约60张卡片它们成为我面试前最好的复习材料。这本笔记的唯一秘诀是越简略越好能用图画绝不用文字。你画一画快排的分区图比抄十行代码更有用。5. 常见问题与排查技巧实录5.1 递归怎么都理解不了该硬背吗不要硬背。递归不是“自己调用自己”这么简单它的本质是“函数调用栈的压栈与出栈”。如果理解不下来我的建议是去找一个调试器比如IDE自带的或者Python Tutor设一个断点一步步跳进递归调用里亲眼观察调用栈每一层发生了什么。用归并排序做实验最好因为它有“递”又有“归”你能看到整个执行过程像洋葱一样一层层剥开再一层层包回去。另一个笨办法是用纸笔展开递归树。比如Fibonacci(5)这个调用你可以画出F(5)分成F(4)和F(3)F(4)又分成F(3)和F(2)……画完之后你就明白为什么直接递归是O(2^n)——因为同一个F(3)被重复计算了两遍。有了这个视觉感受再引入记忆化搜索、动态规划就顺理成章了。5.2 动态规划的状态定义总是找不到怎么办这是新手最常见的卡点。我的经验有三个“弱智”技巧问自己这个问题的输入是什么输入是数组还是字符串那就大概率以索引为状态维度输入是区间比如“从i到j的子串”大概率是二维区间DP。问自己我最后一步做了什么以爬楼梯为例最后一步要么跨了一级要么跨了两级所以f(n) f(n-1) f(n-2)。编辑距离最后一步要么替换、要么插入、要么删除所以状态转移方程围绕这三种操作展开。大多数DP题的转移方程都可以用“最后一步”这个视角推导出来。先写暴力递归再改DP。不少DP题先用递归备忘录写成再把递归改成迭代填表就完成了。这个过渡很丝滑比直接凭空想转移方程简单得多。5.3 图论算法学了就忘本质原因是啥图论算法忘得快基本是因为没有建立“图 抽象关系”的直觉。图的节点可以是城市、网站、人、状态边可以是道路、超链接、人际关系、动作。如果你只把图看成“一堆圆圈和箭头”那你学Dijkstra就是在“背模板”能不忘了。我的建议是给每个图论算法配一个具体的“非典型场景”DFS/BFS → 迷宫寻路、联通块拓扑排序 → 课程先修顺序、编译依赖Dijkstra → 地铁最短换乘Floyd → 任意两地的最短直达价格Tarjan强连通分量 → 游戏中哪些账号构成一个“死循环群聊”一旦这些场景扎根在脑子里再去套算法代码就不会再感到抽象了。5.4 刷题刷了很多但面试还是写不出来这个问题非常真实因为它指向“输入性刷题”和“输出性刷题”的区别。你可能看了很多题解你以为你会了但关上屏幕一片空白。这不是记忆力差是缺少“从零开始构建”的训练。我后来强制自己用“白板模式”刷题不看IDE的语法高亮、自动补全、编译提示直接在编辑器里新建一个空白文件从上到下把函数签名、循环、边界条件全部敲出来一次写对不允许试错式地“改几行跑一下”。这个过程刚开始非常痛苦但大约坚持三周后写代码的连贯性和代码的准确度会明显提升。还有一个更狠的办法限时15分钟写出暴力解然后再花15分钟优化。面试考点的本质不是难题偏题而是你在有压力的情况下能不能写出可工作的代码。平时这样练面试才不发慌。5.5 数学基础不够算法要不要先停下来补高数不要停。这是我踩过得比较深的坑。我在学机器学习的时候一度陷入“要看懂所有推导”的执念结果花了两周去翻概率论和线性代数教材然后发现自己把算法的Coding都落了。后来我调整策略先知道这个数学公式是干什么的再在需要时深入查细节。比如SVD分解你不需要先精通线性代数再学推荐系统你只需要知道“SVD能把一个大矩阵拆成三个较小矩阵的乘积用于降维”就够了。等到面试里真遇到“说说SVD在推荐里的应用”你再补特征值、奇异值的细节也来得及。学习路径上“用”永远是第一位的“懂原理”排在后面。6. 51天学习法的复盘什么可以坚持什么必须放弃聊了这么多算法细节最后我得说说这51天的学习体感可能比技术本身更值得参考。这51天我坚持下来最重要的是三件事第一每天固定时间学算法雷打不动。我选的是早上出门前那40分钟——头脑最清醒用来读贪心、写DP、推KMP都合适。晚上太累、周末太散都不如早晨稳定。算法学习最怕“三天打鱼两天晒网”因为它的知识链条特别长断两天就跟不上。第二每天只学“一招”绝不贪多。所谓“招”指一个算法的最核心思想比如“归并排序的分割合并”、“Floyd的中转点枚举”、“KMP的最长相同前后缀”。一天学一招一招吃透比一天扫十个算法再忘八个强太多。只有当你能用自己的话把这个“一招”讲出来才算今天完成任务。第三每周花一天做“乱序复习”。我从抽屉里随机抽卡片随机做3道不同类型的题不限定章节这样就逼自己在脑子里建立“跨算法检索”的能力——不是按目录找答案而是按问题特征找答案。这一招是我认为51天里收益最高、最反直觉的练习。必须放弃的是什么呢一是放弃“看懂等于学会”的幻觉。任何算法只要我没能合上书写出来、没有亲手跑出正确结果我都视作未完成。这个标准一度让我很灰心但通过率恰恰暴露了我的学习盲区。二是放弃“追求完美笔记”的执念。我早期花了大量时间把笔记排版得漂漂亮亮后来发现这种笔记基本不翻开看第二遍。真正有用的笔记是黏在算法旁边的注释、随手画的示意图、调试时的报错记录。请记住笔记是给未来的自己看的“思维快照”不是出版书籍。三是放弃“一刀切刷题量”的虚荣。我试过LeetCode每天10题过瘾但三天后几乎全忘。同样时间与其刷10道水题不如把1道难题从暴力解、到优化解、再到面试口述梳理流畅这个深度大于那个数量。如果你也在学算法我的忠告是别怕慢怕的是用“看起来很勤奋”的方式原地踏步。每天一片面包慢慢叠成一座面包山总有一天你回头看会吓一跳。51天不算长但它足够证明这个“更弱智”的笨办法真的能让你从算法门外汉变成一个敢在面试官面前坦然写代码的人。接下来我打算继续往深度方向走刷穿动态规划题单、补完Tarjan的边双联通分量、把强化学习从Q-Learning推到策略梯度。这条“更弱智”的学习路还没走完如果你也在路上一起慢慢爬。