为什么你学算法容易忘?
The following article is from Coder梁 Author 梁唐
作者 | 梁唐
出品 | 公众号:Coder梁(ID:Coder_LT)
最近在知乎上看到一个很有意思的问题,叫做“程序员怎么记住众多代码的?”
我相信对于在座的萌新程序员来说,可能更想知道的是,为什么我学了新的算法总是容易忘?大牛们都是怎么做到的?今天就和大家聊聊这个话题,希望能够帮助一些同学解除困惑。
心理表征
在著名的畅销书《刻意练习——从新手到大师》一书当中提到了这么一个案例。说是在导航软件出现之前,伦敦的司机有一项超能力,可以瞬间反应出到达目的地的最优线路。要知道伦敦是国际化大都市,城市交通网错综复杂。要记住庞大的路线、地图已经足够困难,更何况还需要快速计算出路径呢?
对于这个问题书中给的解释是心理表征,这是一个英文翻译词,因为文化隔阂的原因导致它比较难以理解。我个人觉得理解成抽象信息更加直观,随着信息的一层层抽象和聚合,信息的密度会增大,信息的体积会随之减小。也就是说信息越抽象,我们要“记”的内容就越少,也就越容易被记住。
伦敦的出租车司机并不是将地图印在了脑子里,而是对伦敦的路线提炼了非常精炼的抽象信息。使得只要一听目的地和当前时间,就能立刻反应出应该选择的最优路线。书中还有一个例子是记棋谱的例子,一些象棋高手可以快速记住一局残局每一颗棋子的位置。然而神奇的是,如果棋盘中的棋子是随机摆放的,他们的表现和普通人相差不大。只有是真实对弈的残局或者局面时,他们才能快速地记住。
这说明了高手们之所以能记住盘面,并不是依靠记忆力记住了每一颗棋子的位置。而是利用了盘面中棋子位置之间的抽象信息,随机摆放的棋子是不包含抽象信息的,而真实对弈的棋局,每一颗棋子摆放的位置相互之间存在一定的逻辑。这些象棋高手可能自己也说不出来这逻辑究竟是什么,但他们正是通过它完成了记忆。
如果大家了解过深度学习,尤其是卷积神经网络的话,会发现这和图像识别问题当中的卷积网络异曲同工。我们知道一张图片包含上百万甚至上千万像素点,每一个像素点都有独立的取值,因此图片的内容千变万化。我们直接从像素点入手想要设计一个模型是非常困难的,因此我们势必要做一些抽象和聚合。这也正是卷积神经网络训练的过程,我们来看下下图。
模型的输入是一系列像素点,第一次抽象,我们会将相邻的像素点聚合,从而得到了一些边。第二次抽象,我们再将相邻的边聚合,得到了一些区域图。第三次抽象,我们再将局部的特征图聚合,就得到了一张完整的人脸。在这个过程当中,模型的参数数量是减少的,相比于输入层上百万甚至更多的参数,输出层可能只有几百个甚至几十个。
这正是因为信息的高度抽象使得模型要“记住”的内容大大减少,到最后,都是高度抽象的信息,根本用不到太多的参数。
在编程和算法领域也是一样的,高手们能力出众依靠的并不是记忆力,并不是因为他们记住了多少算法。算法题千变万化,只靠记忆是不够的,高手们和伦敦的出租车已经象棋高手一样,依靠的是对心里表征或者说高度抽象信息的驾驭。
联想能力
有一句著名的广告语,叫做人类失去联想,世界将会怎样。不考虑商业成分,单纯看字面意思,这句话毫无毛病。联想能力几乎能和思维能力画等号,这也是算法高手们的杀手锏所在。
前面说了算法高手之所以能力出众,并不是依靠记忆力,靠记住了多少算法,而是依靠的抽象信息。那么在我们思考问题的过程当中,这些抽象信息是怎么起作用的,或者说高手们是如何进行思考的呢?依靠的都是本能吗?当然不是,依靠的是联想。
普通人的大脑当中,知识是以点状图分布的。当遇到实际问题时,能想起来的只有那么几个点。而高手的思维当中,知识同样是以点分布的,只不过和普通人不同的是,高手会用联想将这些点串联起来,组成一张知识网络。遇到问题时想起来的就不再是几个零星的点,而是一大片知识网络,因此更容易获得启发想出解法。
比如我们来举个例子,我们遇到了LeetCode中一道题。普通人读完题目之后一旦没有思路,就会陷入干想。他们知道要分析要推导,但完全不知道从何下手,只能瞪眼干想。而高手们呢?由于他们的知识体系非常紧密,读完题之后可能瞬间就联想到了几道类似的问题,或者是常用的一些解决方案,脑子里能有好几种想法。之后只要把这些想法一一验证,过滤掉不可行的。
如果这些想法都不可行,那么就进一步分析它们不可行的原因,再从这些原因出发继续联想。如此操作往复多次,往往解法也就浮出水面了。
看到了吗,不是在记忆里检索学过的算法生搬硬套,而是分析问题,通过联想寻找解法。
原理大于一切
通过前面的论述我们已经知道了,思维能力由两个部分组成,一个是知识点,另一个是联想能力。那么想要提升能力也可以从这两个角度针对性地入手。
专题练习
虽然我们说学算法不能靠死记硬背,但并不是说记忆力不重要。一个算法我们完全都没听说过,自然也就很难解决它适用的相关问题。想要拓展知识面,别无他法,只有依靠学习和练习。
但学习和练习也是有技巧的,并不是机械的越多越好。由于篇幅原因,这里只说一个最贴切的——重质不重量。
字面意思是更加看重质量而非数量,深挖一点来说是更加看重理解,尤其是核心原理的理解。核心原理是算法领域抽象程度最高的信息,最有含金量,将它记住的成本最低。比如很多同学觉得动态规划很难,种类很多,千变万化。但它的原理很简单,无非是状态转移和最优子结构两点。我们深入理解了原理之后,剩下的只需要根据实际情况随机应变即可,根本不用拘泥于代码形式。
想要达成这点,最好的方法是专题练习。每次只学一个算法,一次把这个算法相关的各种变形问题都做一遍。把当前算法的原理搞懂吃透,一般来说一个专题做完之后,算法也就完全记住了。
发散练习
发散练习针对的是单个题目,大多数情况下,一道问题往往有多种解法。通常情况下,我们最容易想到的是我们最熟悉的算法。不少同学追求刷题数量,一旦通过题目就放在一边了,也不会再去深入思考尝试其他解法了。
在一道已经通过的问题上继续花功夫,怎么看都是无用功,但事实并非如此,这也是很多acm大牛常用的训练方法,叫做发散练习。
这么做的好处很明显,首先可以帮助我们开拓视野,一个是可以增强一些我们不太常用的算法的练习,另外一个很重要的理由是,很多时候不同的算法意味着不同的思路不同的推导过程。我们把几种方法都写出来,互相对比,不但对问题理解得更加深刻,也可以让我们对算法本身加深认识。很多时候会有“原来这题也可以使用这种方法”恍然大悟的感觉。
还有一些大佬在练习的时候,会强制自己使用某一个算法。明明不是动态规划的问题,也想尽办法用动态规划去解释去思考。明明不是网络流的问题,也通过网络流去建模。通过这种方法逼自己开拓视野,增加对算法的理解和熟悉。动态规划和网络流非常经典,适用面也非常广,号称一切问题都可以使用这俩来建模。虽然略有夸张,但这种做法却很值得我们借鉴。
这几年随着互联网行业发展越发成熟,国内大小公司对于算法问题以及思维能力的考察也要求越来越高。越来越多的公司会在面试当中进行算法题和思维题的考察,因此想要成为优秀的工程师,斩获知名公司offer,算法能力的提升和补充非常重要。
<END>
“
大家注意:因为微信最近又改了推送机制,经常有小伙伴说错过了之前的文章,比如一些送书的限时福利,错过了就是错过了。
所以建议大家加个星标,就能第一时间收到推送。👇
常见的算法优化套路,用空间换时间
面试必会的算法题——求加法
世界上最伟大最邪恶的软件发明
GitHub 被超火的 ChatGPT 霸榜!
Office 2019/2021专业增强版,正版终身授权!