
以下文章来源于满赋诸机 ,作者idealism xxm
大家好,我是小满。LeetCode 竞赛积分全球总排名前 1000 ,单场竞赛全球排名最高 70 。
今天的文章会分享小满如何刷正确刷算法题,精进算法能力。
小满在 如何将无效努力转变为刻意练习 提到刷算法题符合有目的练习的四个特点,所以我们常常会无意识地刻意练习,而刻意练习是快速精进一项技能的关键。
刷算法题的不仅可以精进算法能力,还能让自己掌握各种算法,保持活跃的思维,甚至能让自己解决日常生活工作中的问题。
那么小满是如何通过刷算法题精进算法能力的呢?
小满精进算法能力的过程和其他学习一样,即将整个过程分成以下五个阶段:
这样就是将精进算法能力的目标拆分成五个小目标,然后逐项击破即可,当然每个小目标内部其实还可以继续拆分,直到我们自己觉得比较容易达成。
1
熟悉模式
学习的本质就是模式识别,而模式识别正是让我们能快速熟悉事物、举一反三的基础,所以当我们最开始刷题时,目标就是熟悉并建立刷题的模式。
小满最开始刷题的时候,目标就是让自己能够轻易通过简单的模拟类题目,直接按照题意实现代码即可。
这一点听起来很简单,但是我们最开始总是很容易犯各种错误,排查起来十分困难,有时候写代码只用了十分钟,但排查了几个小时还没找到问题。
这就十分打击自信心和积极性,这就要求我们不断给自己打气,最好能找个一同训练的人互相帮助,这能让我们坚持下去。
当然越早遇到这样的问题,越有利于我们尽早纠正自己的坏习惯和错误认知。
小满现在看到当时写的代码时都觉得有点不堪入目,这正说明了小满在这方面取得长足进步。
小满当时在大一寒假刷的是杭电 OJ 第 11 页 ( http://acm.hdu.edu.cn/listproblem.php?vol=11 ) 的 100 道题,刷完之后基本就熟悉了刷题的模式。
这里面的题很多都类似书本上的练习题,不过由于 OJ 有及时反馈,我们更容易坚持全部完成。
现在更推荐大家直接在 LeetCode ( https://leetcode-cn.com/problemset/all/ ) 上从简单题开始刷,因为 LeetCode 平台会给出错误的用例。
这种反馈对于初学者来说非常友好了,不必自己反复阅读代码、苦思冥想各种可能的错误用例,让我们专心分析代码出现的问题。
而且 LeetCode 平台本身就有各种非常基础的免费 LeetBook 和学习计划,并有《剑指 Offer》 ( https://leetcode-cn.com/study-plan/lcof/ ) 和《程序员面试金典》 ( https://leetcode-cn.com/problem-list/xb9lfcwi/ ) 两本书的配套练习,能让小白轻松从入门到精通。
这一阶段的目标不是学习各种算法,而是熟悉刷题的模式,并不断强化自己非算法相关的能力:细心程度、编码习惯、思维方式、调试能力、查错能力等。
2
专项练习
当我们已经对刷题模式轻车熟路后,就进入到下一个阶段,目标也就转换为专项练习,也就是针对薄弱的算法或者想要学习的算法进行针对性训练。
比如想要掌握动态规划的算法,那就直接从最基础的动态规划题目开始完成,然后逐步加大难度即可。
小满当时学习动态规划时就先从背包问题开始,而背包问题又可以细分为 01 背包、完全背包和多重背包,小满针对每一个类型都刷了很多题去熟悉理解其中的原理。
掌握了背包问题就算基本入门了动态规划,接下来就需要针对其他类型的动态规划进行练习,让自己能够真正理解动态规划。
区间 DP 、状压 DP 、树形 DP 、数位 DP 等等都是不同类型的动态规划,小满当时都有进行过专项练习。
当时学起来觉得挺难的,不过现在前三个类型都变成了 LeetCode 的中等难度的题目了。
面对这么多的类型不要慌张,把它们当作专项练习这个目标下的细分小目标,一个个慢慢突破掌握即可,目的是让自己在知道能使用动态规划时就能想到如何解题。
这一阶段的目标就是让自己真正理解某一种特定的算法,并能够熟练地完成对应算法的代码。
这个阶段可以和后续的阶段并行,因为算法非常多,我们肯定无法全部学完。而通过后续的阶段,我们可以更清楚地认识到自己的薄弱环节,这样就更有动力在对应的专项练习上投入更多精力。
完成专项练习后,我们基本已经能轻松解决对应类型的题目了,接下来可以继续专项练习其他类型的题目,也可以将其融入到实战模拟中。
3
实战模拟
经过前两个阶段,算法才算真正入门了,最难的地方才慢慢开始。实战模拟则是第一个要跨越的门槛,这个阶段的目标就是让自己真正理解算法的使用场景。
在专项练习中,我们预先得知了每题应该使用的算法,我们只需要将题目套进对应的算法模版即可,但推导出一道题目应该使用的算法在很多场景下恰恰是最困难的。
在实战模拟中,我们并不知道题目的正确解法是什么,所以就得分析题目的各种信息——题意及细节、数据范围、数据特点等。
在此基础上猜测各种可能的解法,并分析每个解法的时空复杂度,保证在正确的基础上不会发生超时、超空间等问题。
这种分析推导能力非常重要,能够有效避免我们走入歧途,让我们减少错误,提高效率。
很多人看到题目后,不分析就直接写了个非常暴力的 的解法,喜提 TLE ,有些人甚至都不知道自己的代码会超时而多次尝试。
小满也曾经由于时间复杂度分析错误出过一次这样的问题,最后花费了大量的时间去写一个错误的代码,错过了正确通过的机会。
如果我们不具备这样的能力,那么往往就会像穿衣服扣扣子一样,扣错了第一颗扣子,后续的扣子都会扣错,而且只能等最后才能发现问题,有时甚至一直无法发现问题。
这种能力是专项练习无法完成的,只能通过大量的实战模拟让自己真正理解算法的使用场景,从而建立起对应的心理表征。
4
融会贯通
等小满能灵活运用这些算法后,就该挑战需要不同算法结合的题目,比如:动态规划 + 二分、动态规划 + 排列组合、动态规划 + 调度场算法、动态规划 + 双指针等等。
这又需要大量的实战模拟后才能掌握,目前小满还处于这个阶段,所以有时候还是会想不到如何结合不同的算法解决问题。
比如前几天小满刚刚日更了一道 需要前缀和 + Map 处理的题 ,但今天日更的另一道同样需要前缀和 + Map 处理的中等题时,还想了好一会儿。
这说明小满没有完全参透这些算法及其使用场景,所以很多时候还是需要根据以往积累的经验,猜测最可能的用到的算法。
小满在读完这道题时第一反应其实就是前缀和,但仅仅这样是不够的,后续又在脑海中组合不同的算法尝试,最终才找到正确的解法。
这几个阶段都要保持自己的练习,尤其是实战模拟,可以尝试每周打一下周赛,体会一下真实场景下解题与训练时解题的不同,这样才能快速提升。
5
条件反射
突破融会贯通这个阶段后,就是让自己真正达到条件反射的程度。
思维上形成条件反射,让自己看到题目就知道解法。
打字形成条件反射,不断提高打字速度,要知道竞赛前面的大佬基本都是拼手速。
其实小满偶尔也会有这样的反射,能以迅雷不及掩耳之势打完,小满其实都不知道打出了什么,但的确是想要的代码。
当然小满是在国际站打竞赛,所以英文能力和理解能力同样需要形成条件反射。
10 分钟可能有人还没读懂题目,但第一名已经全部通过了,这样的情况常常出现。
小满知道有一次竞赛,一位大佬在 5 分钟内就通过了全部 4 道题,恐怖如斯。
不得不感叹,人与人之间的差距有时候比人与猪的还大,在天赋和勤奋两方面都是如此。
6
小结
今天小满分享了自己精进算法技能的五个阶段: