刷题交流 | 2700 分总结 & 算法入门
16930
2022.12.16
2023.01.27
发布于 未知归属地

这篇文章最开始是打算在拿到 Guardian 勋章的时候写的,只是当时不确定是不是因为偶尔发挥好才上分的,因为那之前刚掉过分怕又掉下去,所以想着等分高一点稳定一点在写,然后拖着拖着就 2400 分了,想想就算了。第二次想写的时候,是在上个月想着到 2700 的时候写一下,然后分数卡在了 2699,并且当时在忙一些别的事,也就搁置了。这几天正好有空,感觉这次可能能进前 100 名,之后应该也很难突破这个成就了,所以抽了点时间把学算法的这段经历总结了一下写成文章,只是最终还是差了十几分,没能进前 100。不过想想还是不等了,人生总是不完美的,之前主要是因为自己的拖延症,一直拖着没去写,这次既然已经开始写了,就接着写完,不拖了。


  1. 算法学习历程

  2. 算法入门

  3. 前提

  4. 学习的核心

    1. 克服痛苦
  5. 学习思路

  6. 学习框架

  7. 基础阶段

    1. 保持信心

    2. 学习方式

      1. 错误的学习方式
    3. 获取反馈

      1. 如何判断自己当前的算法水平
  8. 进阶阶段

    1. 快速完成前三题
    2. 突破第四题
  9. 是否用 JS 刷题的建议

  10. 感谢 & 推荐

算法学习历程

以下是我学习算法过程中一些比较重要的节点:

  1. 2021 年
    1. 09 月份开始持续刷题
    2. 10.03 开始打周赛
    3. 11.14 第 267 场周赛第一次 AK 比赛
    4. 12.26 第 273 场周赛第二次 AK 比赛,并且拿到 Knight 勋章
  2. 2022 年 05.22 拿到 Guardian 勋章

我把我整个算法学习过程分为三个阶段:

  1. 第一个阶段:学习基础算法的阶段。这个阶段大概花了两个多月,其实当时只是完成了部分的基础算法学习,像基础的图论、数论的知识我是在比较后面的时候才补上的。
  2. 第二个阶段:想办法能够快速解决周赛前三题。主要是通过模拟周赛和随机刷题,然后在这个阶段会安排每周去学习一个进阶的知识点。这个阶段花了两个月左右的时间。
  3. 第三个阶段:为了训练思维能力、突破第四题,然后是补充像数论、图论之类的基础知识,以及算法的证明等等,训练则主要是去 Codeforces 上刷构造题。这阶段就持续了比较久的时间了,大概持续了近五个月的时间,一方面是我自身基础不太好,需要补的东西比较多,另外一方面中间也走了一些弯路,去学了一些比较偏的算法浪费了一些时间的。
  4. 后面直到现在,虽然也刷了挺多题的,一方面其中有很多水题,另外一方面要到下一个阶段,我目前的知识储备还差的挺多的,加上最近两个月也没有太多时间放在算法上,就是做做每日一题,打打周赛,所以一直没有什么本质上的突破。

在整个算法学习的过程中,第一个阶段是我感觉最充实的一段时光,差不多是最初的两个月内,每天都能学到新的知识、有所收获,一两天就能掌握一个知识点,每天能够明显感觉到自己的进步,这也是最初的那段时间里面让我坚持学习的主要动力。

后来就很难能够在短时间内频繁的感觉到提升了。对于进阶的知识点,每个知识点掌握周期往往是以周为单位,甚至更长;而对于能力的训练,也往往是需要长时间刷题的积累之后,才能真正感觉到提升。在这些时间里面,最主要能够刺激我前行的动力,一方面来源于能够独立解决题目的成就感,特别是解决那种对自己来说有点难的,但凭着自己一点点去分析、优化最终能够 AC 掉,那一瞬间感觉是真的很有成就感。另一方面则是来源于周赛,每次参加周赛总是有一种热血沸腾的感觉,以及 AK 时那种刺激的感觉,每当我不想刷题的时候,我就会去想想这种感觉,就能让自己多刷几题。

在完成第三个阶段后,我感觉自己才真正进入的算法世界的大门。之前很多题目都是凭感觉、凭经验去解答,而现在能真正去分析题目,选择合适的算法,并且有能力去证明为什么用这种算法是正确的。

当然主要是一些简单中等的题,难的题很多时候也还是要靠经验去猜。另外比赛的时候,基本上也是大致想一下这样做是对的,不会特别严谨的去证明,一般是在 AK 之后,再去想比较严谨的证明。

算法入门

如果你目前还没有任何方向,比较迷茫,不知道如何开始去学习算法,那么可以以此作为一个指南,这也是这篇文章的主要目的,将我学习实践的过程,总结成行之有效的一套方案,希望能够帮助你少走一些弯路,更容易的入门。

如果你已经有在学习某个算法课程,那么建议以你正在学的课程为主。或者你有老师在带你的话,也建议以你老师的规划为主。当然你可以以这篇文章作为参考和对照,也许能够反映出现有的规划中的一些不足之处,那这篇文章对你来说也会有所价值了。

这里的入门,主要是指周赛 1800 分以下的阶段,当分数打到 1800~2000 的话,至少是大概率能够稳定并且比较快速的 AC 前三题了,这个时候对于基础算法的掌握已经相当不错了。而从 2000 往上就开始慢慢往进阶阶段去走了,这时候需要依赖于对第四题的突破。

对于进阶的部分,我涉猎的也不多,只能提供一些我自己经验,可以参考后面进阶部分的内容,希望能帮到你。

每个人具体遇到的情况可能会有所不同,有可能有些情况我没有遇到。如果有任何问题或者疑惑,欢迎通过评论或者私信进行交流~~

前提

每个人可能都有自己的偏好和目标,可能有的人学习算法,是为了享受这个过程中自己去创造一些算法的乐趣;有的人是为了能够享受从文献中去追根究底的乐趣;有的人只是当作兴趣爱好,作为闲暇之余的业余活动等等,我觉得本身并没有对错之分,只要能够达成自己想要的目的即可。

而我的目的其实很简单,就是为了高效的提升算法能力,后续内容也都是以此为前提进行的。

比如看题解这件事情,我觉得完全是没问题和没有任何心理负担的,只要符合当前的目标即可。比如在基础算法的学习中,本身就有非常多的知识是我们不会的,这时候我们的目的是为了能够去学习这些知识点,在进行一些时间的思考之后没有思路的话,去看题解是完全没有问题。当然不是看完题解就完事了,我们需要从题解中去获取反馈,从中分析出我们究竟是因为什么问题导致没有思路,然后去解决它,从而帮助我们提升自己,这正是学习的目的。

另外以下内容针对的是算法零基础,而不是编程零基础。我觉得至少掌握了一门语言的编程基础,再去学习算法会比较合适。其实也不需要非常精通,对基本语法、判断循环、字符串、数组、函数等有一些基本的认知和实践即可。即使完全没有编程经验,一般来说花个一个礼拜去学一下应该都能达到的程度。

学习的核心

学习的过程,就是不断重复的过程。

对于学习算法来说,一个最基本的思路,就是去找到自己不会的知识点,通过学习去学会它;找到那些不熟练的操作,通过刻意练习,去形成肌肉记忆;对于不熟悉的思维套路,找到类似的题,去多做几次,不断去熟悉直到掌握这个套路。总结起来就是找到一个弱点,通过学习或不断的练习,直到克服这个弱点为止,然后不断重复这个过程。

克服痛苦

在整个学习的过程需要不断克服自己的惰性、拒绝其他的诱惑、强迫自己集中精神去思考等等,肯定是不会太舒服的,大多数时候都是痛苦的。

但在这个过程中,我们可以通过去抓住一些其他的情绪,去覆盖或者忘记痛苦的感觉。

在最开始的时候,我主要是以好奇心作为动力来驱动自己去学习,学到新知识的愉悦的感觉往往会比这个过程中痛苦的感觉要强烈很多。而每次能自己独立做出题时的成就感也是非常强烈的,体验过后,往往希望能够再次体验到这种感觉,这也是我学习和训练的动力之一。参加周赛带来的反馈,如果那一周考的好了,就会非常开心,然后有动力继续刷题;如果是考的不好,则会很沮丧,这时候就会想着下次一定要考好,也会有动力去刷题。

这里我只是提供一些参考,每个人的体验可能都会不同,比如像我这样会对上分或者掉分感到比较强烈的情绪,则可以加以利用,可能有些人对周赛成绩不是有很大触动,则不会有这种感觉。所以需要根据自己实际的体验,找到可以利用的点,将其转化为对自己有利的决策。

学习思路

正确的学习思路是要根据不同的能力,去使用不同的方式去掌握(以下描述将知识点也统称为能力的一种)。我觉得算法能力并不是单一的某种能力,而是多方面能力的综合体现。包括数学、算法等理论知识;还有思维、逻辑等比较抽象的能力;以及编码、调试等实际操作的技巧。

其中不同的能力,需要不同的方式去学习和掌握,比如对于知识点,需要先去学习对应的思路,然后通过训练达到掌握的程度;而对于像思维能力这样比较抽象的能力,则需要通过大量的刷题来进行训练,相对的学习知识点的成分占比较少。

并且有些能力之间会有先后之分,比如某些比较难的知识会以某些比较基础的知识作为基础,那么先学基础的知识再去学难的知识是一个比较合理的顺序。

学习框架

对于不同的能力,是需要用不同的学习方式去掌握的,但在整体上,有一个大的框架是可以重复使用的:

  1. 制定目标和计划
  2. 通过学习和训练完成计划
  3. 通过某种测试获取反馈
  4. 根据反馈判断是否达成目标,如果已经完成目标则开始下一个能力的学习,否则去分析哪些地方没有达成目标,然后调整计划,直到达成目标
  5. 过一段时间回头来复习

其中第二点对于不同的能力可能会不同,有些能力需要制定学习和训练的计划,而有些能力可能只需要进行训练的计划。而第五点,则主要是针对知识型的能力,以及一些不太常用的技巧之类的。

这个框架大家应该是非常熟悉的,其实我们从小到大的学习,都是用的这一套框架,只是其中很多部分是由老师这个角色去完成的,而我们只要跟着学、完成练习、去考试就可以。但学算法的话,大多数情况是没有老师这个角色存在的,我们需要自己去完成那些原本是由老师来完成的工作,比如去定目标、根据不同的内容制定不同的学习计划、给自己安排测试、主动去获取反馈等等。

以下是基于我自己学习过程中,根据自己的情况进行分析得出的结果,并不一定适合每个人,也许你的情况跟我类似,可以参考借鉴。也许你会遇到不同的情况,那就需要根据自己具体的情况去分析。

基础阶段

  1. 保持信心
  2. 主线由易到难
  3. 对于每个知识点:先学习,在实践,最后测试反馈
    1. 高效的学习
    2. 重复练习
    3. 主动寻求反馈

保持信心

我觉得对于初期的学习来说,保持学习的信心是非常重要的。

如果你感觉自己一直学不会算法,花了很长时间也没有多少提升,那么非常有可能只是因为学习方法不对而已。正确的学习方法,会让初学者以简单模式的开局,而错误的学习方法,则有可能让初学者以地狱模式开局。以地域模式开局,有可能长时间无法获取正向反馈,然后非常容易产生自我怀疑,觉得自己是不是没有这方面的天赋,不适合学习算法,从而导致被劝退。

我当初也是被错误的学习方法劝退了好几回,当我掌握了正确的学习方法之后,才发现其实并不是自己天赋不够或者是太笨了,而仅仅是因为用错方法而已。

另外关于天赋的思考,我觉得至少力扣 2000 分以下,应该都不存在天赋的问题,区别只是天赋好的同学可能两三个月就能打上来,而咱这样天赋一般的,可能需要花个大半年的时间,但至少这不是一个完全不可达的目标,完全是可以靠勤奋弥补上来的,只是看是否愿意投入时间而已。其实 2200 分我觉得也完全不存在天赋问题,只是需要正确的训练和更多时间。当然这里都是指用正确的学习方法,如果是用了错误的学习方法,掉到某个大坑走了弯路,有可能会被浪费很多时间。

学习方式

学习的过程有很多时候是痛苦的,而一个好的学习方式可能不会降低学习的痛苦,但至少不会增加学习的痛苦

我觉得对于初学者来说,主要的目标是要掌握基础的算法知识点,我们在解题的时候,如果一个题目要求的知识点都没有掌握,那么大概率这题是做不出来的。掌握对应的知识点,是能解出一题的基础,所以这也是初学者首先需要去学习和掌握的。而要掌握一个算法知识点,除了要掌握其对应的思想,还要掌握其实现,毕竟我们最终需要能让程序运行起来才行。

为了完成这个目标,推荐使用以下的方式去学习,这也是我平常在学习算法知识点时用的方式。

  1. 「整体上的规划」

将基础算法的知识点按照算法的难度、进阶、组合等关系有层次、有规划的进行学习。

当我们踏入一个陌生的领域的时候,会有非常多不会的知识点。我们虽然能同时做很多事情,但学习的话,专注于一点去学习往往能取得更好的效果。从这点来说,我们是单线程学习的,那么对于这么多不同的知识点,我们就需要有一个先后顺序。这也是为什么我们需要有计划的进行学习。

我觉得一个比较好的学习顺序,先去学一些简单的、作为底层基础的知识,然后在此之上去学习一些稍微难一些的、或者是已经学会的基础上扩展的知识,这样一点点去学习是最好。

关于具体的学习顺序,对于初学者来说自己去规划还是具有一定困难的,可以参考后面我给出的几个参考链接,或者通过搜索引擎自行搜索。

  1. 针对「每个具体的算法知识点」

首先去学习算法的理论知识以及实现。然后去刷该算法对应的模板题,并且要反复多刷几遍,通过这个过程,可以达到两方面的目的:一方面可以检验自己对于算法的理解是否正确,有错误的地方需要及时改正;另一方面完成对算法实现的基本掌握。最后去刷这个算法对应的扩展题,这个过程主要是提升对于该算法掌握的熟练度。完成这一套流程之后,能达到的效果是,给定一个该算法的题目,基本上就能解出来。

  1. 针对「每一道题目」

可以稍微花一点时间看看有没有思路,即使是朴素的解法也没关系,可以先写出来,然后再一点点去优化。给自己设定一个时间(比如 20 分钟),这个时间内都没有任何思路的话,建议直接去看题解。一般这种情况下,要么是解这题的某个知识点没掌握,要么是需要某种特殊的思考角度之类的,继续想下去也不大可能想的出来,就没必要再继续浪费时间了。通过看题解去分析自己具体是因为什么原因解不出来的:如果是因为某个知识点没有掌握的,那么去学会它;如果是因为有些地方理解不对,那么重新去梳理一下;如果是因为某个思路没想到,那么记住这这个思路。当然如果看到题解中的一些信息,发现自己有了思路了,也可以停止继续看题解,按照自己的思路再去试试看,但是建议这个过程还是不要花太多时间。这个阶段要承认我们是有很多东西不会的,需要去学的,很多东西光靠自己想是想不明白的,或者即使能想明白,也需要花费大量的时间,不如直接去学来的快。这也是保证学习效率之一,而学习的效率则能保证自己能够在规定的时间内完成目标,从而保证自己学习的信心。

当然不是看完题解之后,这题就这么过去了,需要在理解题解的思路后,自己能够在不看题解的情况下,根据思路独立写出来。另外对于这种看题解才写出来的题目,一般需要重点标记一下,过几天回来重新做一遍。因为是看题解之后,才有的思路,很可能只是当时记住了,很容易过一段时间就忘了,这种就非常需要靠复习来巩固的。

  1. 目标

对于模板题的要求是练到肌肉记忆,也就是当你下次看到这题时,可以不加思索的写出来,这是算法的基本功。像周赛前排的大佬,经常能用极短的时间作出周赛四道题,就是因为通过大量的训练,把算法训练到肌肉记忆的程度,基本上看完题目,就能想到用什么算法,然后很快把算法实现出来。

而对于扩展题的要求是,能够独立实现出来。当然对于过程来说不管你是通过自己想出来的,还是说看题解之后才想到的都没关系,这个时候能做到前面对应的要求独立实现出来,就算完成当前阶段的目标,既掌握这个算法知识点。

  1. 扩展

这个学习过程,是一个循序渐进、由易到难的过程,尽量减小学习过程中所要跨越的高度,使得学习曲线更加平滑。

另外推荐看一下覃超讲的《如何高效学习数据结构与算法》和《如何用好 LeetCode》,其中会有更多细节。我最开始也是通过这个视频,才了解如何正确的去学习算法。我学习算法的实践过程中,也都是以视频中讲的方法为基础去扩展开来的。

关于计时,如果每次刷题需要自己刷动去开启计时会略显麻烦,这里推荐一下我开发的浏览器扩展Refined LeetCode,其中有一个计时功能,会在每次打开答题页的时候,自动开始计时,当提交成功之后自动将耗时记录到备注中,整个过程不需要手动操作,非常方便。扩展还有一些其他功能,具体详情可以查看帖子 力扣浏览器扩展 Refined LeetCode 介绍

错误的学习方式

举一个错误的学习方式的例子,当初我也是掉到这个坑里面,被劝退了好几回。

有一种非常坑但非常常见的方式,就是让人直接去刷题,这种方式就会让初学者以地域模式开局。这种方式的学习效率非常低,除非天赋较高,并且有一定的基础(包括编程基础、数学基础、算法理论基础等等),才比较有可能用这种模式开局,并且能坚持下去的,不然大概率会被劝退。

这里仅仅针对初学者来说,在学习算法的过程中,有些阶段需要去大量的刷题,从刷题的过程中去获取反馈。比如在学会大多数基础算法之后,需要提升前三题的解题速度,这时候就需要通过大量刷题去见识不同的题型;或者是要提升思维能力的时候,需要通过大量的刷题去训练等等。

获取反馈

在学习的过程中,获取即时反馈是非常重要的。反馈分为主动型反馈和被动型反馈,主动型反馈就是根据自己主动去获取反馈,而被动型反馈,则是别人给你的反馈,比如读书的时候老师给我们批改作业,告诉我们哪里错了。在算法学习过程中,被动型反馈是比较少的,大多数时候算法都是靠自学,很难找到别人给我们做代码审查,即使身边有这样一个人,也不可能一一去看我们写的每一段代码,相对于我们刷的题来说,占比也是比较少的一部分。

当然如果你身边有能够帮你审查的角色,那真的是非常幸运,特别是对于基础阶段来说能这样直接获取的被动型反馈是比较难得的。

还有另外一种方式可以去获取这样的反馈,那就是写题解,把题解发布出来,比如力扣的题解区,去接受其他人的审查。当然这种方式的缺点就是可能反馈会来的比较慢,但不失为一种补充。

除此之外大多数时候,是需要我们去主动寻求反馈的,比如:

  • 对于每一题,我们通过提交去获取反馈,验证我们的解法是不是正确的
  • 提交成功之后,我们可以到提交详情页以及题解区中去查看别人的代码获取反馈,看看自己的实现是不是有哪些可以改进的地方
  • 对于每一个计划,我们需要通过独立去完成扩展题获取反馈,以验证自己是否完成了学习的目标。
  • 对于每个阶段,我们需要通过反馈去了解自己当前的算法水平

如何判断自己当前的算法水平

要了解这个信息,我觉得是比较难的,很多时候我们对于自己处于一个什么水平是比较糢糊的,更别说让别人来判断自己的水平。

对于基础阶段来说,衡量一个人的算法水平,主要看的是掌握了多少算法知识点。所以我觉得基础阶段,计算掌握了多少算法知识点是一个比较不错的衡量标准。你可以把所有的基础算法知识点列出来,然后一个个根据自己掌握的程度去判断,最后看看有多少是自己真实掌握的,有多少是自己还没有掌握的。

判断一个知识点是不是已经掌握了,一个是可以看自己的感觉,当然如果有时候感觉不准的话,其实可以通过去找一个这个知识点的扩展题来做一下,看看能不能做出来,最好是之前没做过的。

另外我觉得周赛的分数是对一个人的算法水平比较准确的体现,至少 2400 分以下还是比较准确的,我一直以来也是以周赛作为一个参考,去制定后续的目标和计划。

当然要通过周赛去反映自己当前的水平,可能需要持续参加一段时间的周赛才行,这样得出的结果才会比较准确。如果只打一两场的话,很有可能正好遇到比较难的,这样可能并不能正确的反应自己当前的水平。不过除了正常参加周赛以外,还可以通过模拟周赛,多打几场,看看自己的排名大概是多少,然后看看那个排名的附近的分数大概是多少,也可以用来作为参考。

进阶阶段

我主要是以周赛作为自己的反馈,去衡量自己的水平,以此来制定后续的计划。整体是以如何 AK 周赛作为目标。我目前的水平大多数时候能做出第四题,但偶尔可能遇到一些比较难的或者状态不好的话,也是有可能写不出来。

要 AK 周赛,其实步骤也简单,就是快速写完前三题,然后把第四题写出来。只是要达到这样的效果,则没有那么简单,需要花时间去不断的学习和训练。

快速完成前三题

我通过前面的方法完成基础阶段的学习之后,能达到的效果是:如果我能想到一个题目所用的算法,那么大概率我能解出这题,但如果想不出来的话,那基本上就解不出来的。这时候在周赛的表现两题三题都有可能,非常看当时的状态,是不是能够看出对应题目所用的算法。

这个时候我的瓶颈主要在如何看出一题所用的算法,这个时候有两种方式可以进行提升,第一种方式是真实提升自己的思维分析能力,第二种方式则是通过刷题量去见识大多数的题型。

我当时没有了解到第一种方式,所以选择的第二种方式。第二种方式相对于第一种方式来说,需要学习的东西比较少,完全靠刷题去练就好了,而且练习的难度也会比较低,通过模拟周赛的方式去练前三题。另外可以参考零神开发的 问题评分项目,去找到跟自己当前分数差不多,或者高一些的题目,去刷这些题目比较有利于提升。

这样练个一个月左右,大概能积累一百多题的刷题量,这时候周赛大概率能够稳三题了,但如果要快速三题的话,可能还需要持续去训练。

而对于上面提到的第一种方式,我也是在比较后面的时候才去掌握这种方式。操作起来会更加难一些,首先可能需要根据自己的基础,去补很多知识,包括数论、图论等知识,还有很多题目的证明等等。之前我们都没有说要非常严谨的去证明我们所学的算法,大多数时候凭感觉也能做出很多算法题,但如果要真正掌握分析题目的能力,则需要学会如何去证明才行,学习证明一方面是能保证自己算法的正确性,另外一方面也是在锻炼自己的思维能力。除了需要学的知识,另外也需要对应的训练。训练的话可以像上面那样去找到跟自己当前水平差不多的题目,或者是稍微难一些的题目。

突破第四题

当我们能够快速解决前三题的时候,就可以想办法去突破第四题了。当然也可以在进行前三题训练的同时,去学习一些进阶的知识点。这个需要根据自己的实际情况去制定计划。

对于第四题来说,主要需要像两方面去突破,一个是进阶的知识点,一个是思维能力。

知识点的选择,可以参考这个帖子周赛第四题小统计 的方法,去统计之前周赛考察的知识点,去一个个学习,这样会更加高效一些。当然周赛第四题的知识点并没有限定在某一个范围内,如果某一周出了之前都没考过的考点,也完全不奇怪。

具体每一个知识点可以沿用之前的学习方法,只是相对来说进阶的知识点会更难一些,学习的时间会更长,而且要达到熟练掌握,往往训练的量也会更多。

至于思维能力,其实上一节的第一种方式,就是在训练自己的思维能力,另外可以参考灵神的分享

想要突破第四题的话,要做好心理准备,这个过程通常会持续比较长的时间。我能大概率解出第四题应该是从今年 5 月份开始的,从我开始去学习进阶的知识点算起,也就是我第一次 AK 的那一周,大概花了半年多的时间,去掉一些训练前三题的时间,以及走了一些弯路,至少三四个月是要有的。

然后这个过程中对于第四题的心态,我觉得可以不用过度强求,这注定是一个漫长的过程。学完一个知识点之后,有可能是好几周以后才会用到,我们能做的就是尽量去扩大自己掌握的知识点的范围,从而增加自己解决第四题的概率,需要等待量变引起质变的那一天。当然每次周赛的复盘还是要的,比如有些题目确实在自己的能力范围内,但却没有 AK 掉,就需要去分析具体的原因,然后解决它,争取下一次不会在这上面犯错。

就像灵神视频里说的,如果不是天才型选手,那只能靠刻苦训练去提升自己,以每一千题作为一个阶段,以 1000、2000、3000 题作为目标去努力。

这里的题目数量主要是指对自己提升有帮助的题,不管是简单题还是困难题都没关系,只要能帮自己提升。比如学习算法时刷的模板题、提升对应算法熟练度时刷的题、检测出自己不会某个知识点时刷的题、复习时刷的题等等。我们需要对哪些刷题是对自己真正有提升要心里有数。当然很多时候在刷题之前,我们并不知道刷这一题是否对自己有提升。这里就要说到上面推荐的题目选择,去刷跟自己当前水平差不多,或者更高一些的题目,刷这样的题目大概率是能够对自己有提升的,要么是能够补上自己的某个知识漏洞,或者是对自己的思维训练有一定的提升。

是否用 JS 刷题的建议

如果是只打算在力扣内刷题的话,我觉得用 JS 是挺不错的,相对来说力扣对 JS 是非常友好的,但如果有打算去其他平台刷题的话,可能 JS 就不是一个很好的选择了,那时候需要处理非常多的极端边界问题,比如对于数字来说,很多题目的数字范围需要处理 64 位的情况,这在 JS 里面是比较致命的,因为 JS 中的 Number 类型大于 53 位后就不准确了,要保证准确就需要用 BigInt 类型,但 BigInt 类型的效率非常慢,有些题目 C++ 用 double 能过的题,JS 用 BigInt 就会超时,所以有些题用 JS 是过不了,这就让人非常郁闷了;还有的算法需要用到递归,而 JS 中的递归深度是非常小的,很多 C++ 直接写递归能过,但 JS 就会爆栈,需要用栈去手动模拟递归,但手动模拟会有一定的效率损失,有些比较极端的题,就会造成超时。力扣中就非常友好的把 JS 的调用栈深度调大了,而其他平台则没有对 JS 进行特别的优待。像这样极端边界的问题还有很多,实际上不止 JS,其他语言也会有些极端边界问题需要处理,但像 C++ 这样正统竞赛的语言,因为刷题者比较多,很多问题会有现成的解决方案。可是进阶的题目中用 JS 刷的人会少很多,遇到这类问题的时候,就需要自己去想解决方案,一一测试,这是非常耗时间的,我记得花的最长时间的一题耗时 4 天,总共提交了一百多次最后才通过。

所以如果是之后打算要往进阶方向去学习的,建议使用 C++ 这种正统竞赛的语言,可以省去很多无谓的时间。当然如果是非要用 JS,也是可以的,就是不要跟我一样头铁,放过一些极端的题目就好。目前来说我遇到的题目里,只有一题没有过掉,其他多花点时间去折腾都能用 JS 过掉(也许是我还没遇到真正难的),有些只是稍微超出一点时间的题目,多提交几次,也能擦着边过掉。

感谢 & 推荐

首先需要感谢有力扣这个平台,友好的界面、即时反馈、优质的题解区和讨论区,是一个初学者进行训练的绝佳之地。不需要处理输入输出、支持大多数语言、能给出完整的错误样例等等特点,也非常有利初学者专注于算法学习这件事本身,而不用分散精力去处理其他一些细节的东西。

另外非常感谢覃超老师,如果当初没有看到《算法面试通关 40 讲》这门课程,可能还一直还在用着错误的方法去学习,从而浪费时间。正是从这门课程中,让我学会如何正确的去学习算法,带我顺利的跨入算法学习的大门。所以我非常推荐这门课程,可以在哔哩哔哩极客时间上看到,前面几节免费试看,其中就详细讲解了如何正确的去学习算法。

在学习的时候,整体方向上是跟着课程走的,但每个具体的小节,则需要根据当前的情况去判断,自己不是真的掌握了对应的内容,如果没有真正掌握的情况下,不要着急去学下一节,要把这一节的内容吃透在往下走。如果是哪里没有理解透,就去找对应的资料,不管是视频、博客、或者跟别人请教都可以,只要能搞懂即可。或者是不够熟练,则可以多给自己找一些扩展题去练习,而不仅限于课程中给出的练习题。

以上是我学习的过程中看过我觉得非常好的并且其对我的学习起到巨大帮助的课程,推荐给大家有需要的话,可以看一看。

当然算法学习并不仅仅只是看课程,还需要靠自己不断的学习和训练,有很多知识和技巧是课程里面没有提供的,这时候就需要靠其他渠道进行获取和学习,其中一个很重要的渠道就是力扣的题解、以及评论区。推荐以下几位,是对我的算法学习过程中帮助比较大的大佬:

  • 灵茶山艾府 通过灵神的分享,我找到了进阶比较关键的方法。并且灵神的题解和每周周赛的讲解让我收获巨大。大家可以关注下 B 站的 「灵茶山艾府
  • zerotrac 🌸 看了零神很多题解,受益匪浅。并且在群里跟零神的一次交流中,纠正了我对时间复杂度的一些错误认知,对我起到了很大的帮助。虽然零神说大概率不会再更新算法相关的视频了,不过可以看看零神之前打比赛的实况。B 站的 「zerotrac
  • hqztrue 从蛙佬的题解中学到了很多知识,虽然有很多题解以我目前的水平还看不懂 😅。

另外在灵神的群里看诸多大佬讨论算法,也让我获益良多。以及力扣上很多大佬的评论和题解让我受益,在此一并谢过。

推荐几个 B 站的 UP 主:

  • 哔哩 winter 前端方向的小伙伴可以关注一下,我最开始学算法的念头,就是听了 winter 老师的公开课产生的。
  • 我是小蜗蜗 我的线段树基础就是从沃老师这里学的。

  • 知识点学习顺序参考
评论 (35)