怎样学算法?
回答前,我们先来举个例子:如何实现“把大象装进冰箱”?
先来看看丹丹老师的“算法”:
说,要把大象装冰箱,总(long)共分几步?
三步。
第一步,把冰箱门打开,
第二步,把大象装进去,
第三步,把冰箱门带上。
在这个“程序”中,大象、冰箱,是数据,而“如何把大象装进冰箱”,就是这个程序的算法。所以,我们可以理解:程序,由数据和算法有机地结合而成,其中,算法,即“计算方法”,是程序的灵魂。作为程序员修炼的“内功”,算法是计算机科学领域最重要的基石之一,是程序员进阶的必修课程,特别是面试时,算法是必不可少的一部分。
当然,丹丹老师说的这三步,我们可以更细致地分解——
算法一:把大象放在冰箱前,把冰箱门打开,把大象装进去。
算法二:把冰箱门打开,把大象放在冰箱门前,然后把大象装进去。
算法三:把大象放在冰箱前,把冰箱门打开对准大象,然后把冰箱向着大象推动直至把大象装进去。
算法四:……
由以上可以看到,实现一种需求,可以设计出多种算法,并且,算法在很大程度上决定了你写出的程序漂不漂亮、巧不巧妙,所以我们学习算法的目的是为了在写程序时能够设计出更优化的方案。
说完What和Why,我们着重来说一下How。对于初学者来说,可以分成三个阶段进行算法的学习,循序渐进,逐步深入。
第一阶段:基于语言去学习数据结构
首先从最熟悉的编程语言入手,推荐Java或C++,去初窥算法。所谓初窥算法,本质上就是要对数据结构有一定的了解。数据结构,就是把数据和算法联系起来的桥梁,比如排序、搜索、回溯、贪心、动态规划、树、链表、队列、栈等等,这些属于计算机科学基础,每位准程序员都应该掌握。同样的数据,如果选择的数据结构不同,就会把我们引导到不同的算法上面。
继续举大象的例子。一个“把十头大象装进冰箱”的程序,首先要解决的问题是:如何存放这十头大象。你可以把这十头大象用绳子挨个串起来,这样即使大象会乱跑,但只要你一直抓着绳子头,就可以顺藤摸瓜,把十头大象都找到;或者,你可以制作十个紧挨着的格子,然后把每头大象依次放到格子中,这样大象就不会乱跑。在这里我们可以看到,同样是存放十头大象,我们设计出了两种不同的方式,这两种对大象(数据)的存放方式,就是“数据结构”。
同时可以很容易发现,这两种数据结构是各有利弊的。比如用绳子的数据结构,你想增加一头大象很容易,只要再串一个大象即可,但是指定某一头大象却很麻烦,因为你不得不从绳子头开始依次查找;而用格子的数据结构,可以很容易找到任意一头大象,但增加一头大象却很麻烦,因为更改格子数量对计算机来说并不是一件容易的事情。所以,不同的数据结构,由于优缺点不同,会直接影响与之适配的算法的好坏。
每种语言都有一些数据结构,因此可以通过自己熟悉的语言先对数据结构进行了解。初学者如果非常想看书的话推荐《大话数据结构》,这本书比较浅显易懂,实在看不懂的东西也不必深究,简单过一遍有个大体概念就可以了,随着积累,之前不懂的东西自然而然就明白了。至于名气极大的《算法导论》和官方课本《数据结构》,细节方面有些琐碎,小白看的话易头痛,易伤自尊,易被劝退,所以不建议小白看。
如果你恰好聪明如谢耳朵,则可以自由选择相关书籍
第二阶段:基于数据结构去学习基本的算法
在对数据结构有了一定了解的基础上,就可以对常用的算法进行学习了。比如最基本的各种不同的排序方法:冒泡排序法、选择排序法等等。在此期间,可以加强对“时间复杂度”这一概念的了解,同时开始学习一些更高级的数据结构。
这些更高级的数据结构所适用的场景更为简单,因此与它们相匹配的算法基本都固定了,比如红黑树、二叉堆等,这些数据结构是否会被使用,完全取决于其时间复杂度的情况。因此熟记它们的时间复杂度可以让你在不同场景下选择最优的数据结构。
同时,你还需要学习与“图”相关的算法,如广度优先遍历、深度优先遍历、最短路径等等。这个阶段,你可以尝试学习经典书籍《算法导论》了。
另外,在这个阶段,建议找个OJ(Online Judge) 尝试做题,遇到问题可以更有针对性的学习。Online Judge会给你一个简单的问题,然后让你编程解决,系统会有很多测试样例。如果你的代码可以通过所有的测试样例,那么说明你的代码逻辑上是正确的。同时OJ都会有一定的内存使用与运行时间限制,过于低效或耗费大量非必要空间的算法将不会通过测试。
选择OJ直接上手做题的好处是它可以给你正反馈。在OJ上,你可以为了解决一个小目标而学。前期可能要用自己没见过的数据结构、没听说过的算法去解决具体问题,这段时间测评系统不会迁就你,你的理解上有一点小小的偏差,OJ都会狠狠的甩你一脸wrong answer。
但同样的,每一个Accept都会让你的大脑奖励自己一份多巴胺,能够让你更快更精准地融会贯通。随着做题越来越多,你的算法熟练度会被锤炼的越来越高,能够更完美的解答新的题目,后期还可以参加一些比赛小试身手。
PS:在OJ上遇到不能通关的算法或数据结构,建议优先找相关视频来学习,其次是技术博客(不过,博客要挑靠谱的来看)。
当然,除以上方法途径之外,你也可以通过课程高效学习算法,从基础出发,强化算法知识,啃完《算法导论》可能要1年,学习这一门课程你只需要1~2个月就能在算法面试脱颖而出了,适合想打好基础与提升自身高度的同学! 精选了几门liuyubobobo老师的算法课程,都在这个专题里面了:走进Google最强AlphaGo Zero算法背后的智能时代 各取所需吧~
第三阶段:基于具体需要和个人兴趣进阶
如果只是要满足基本使用或大多数工作中的需求,那么完成第二阶段基本就足够了(除非你是专门研究算法的)。
到了进阶阶段,更多的是对算法能力的拔高与探索。在此期间,你会触及到人类目前在算法领域的瓶颈区以及一些更为高级的数据结构。在这一步,建议你除了熟读《算法导论》外,还要继续阅读其他书籍,包括一些学术论文。
你可以继续深入探索基础算法,参加ACM比赛获得奖项;也可以用你练就的扎实编程基础去实现一些高级点的思想型算法,比如遗传算法,模拟退火等去解决实际的一些问题;还可以读个研究生深入某个方向去研究计算机视觉,自然语言处理、数据挖掘、分布式等等对数学要求较高的算法,这些都可以让你成长为一名优秀的算法工程师。
祝君学有所成!~