大师兄

开篇词 | 解决这三个误区,才能真正学好算法!

你好,我是胡光。欢迎来到我的算法课!

我曾经是百度高级算法研发工程师。在百度期间,我开发了部门内部的第一版推理引擎,并顺利在人物关系推理等应用场景中落地实施。

说起来,我的算法之路很早就开始了。高中上大学,我靠的是算法竞赛的保送名额。大学期间,我还参加了ACM国际大学生程序设计大赛,拿到了亚洲区金牌,进过两次 ACM 全球总决赛。可以这么说,我的算法知识,是在激烈的竞赛环境中积累起来的。

现在,我是一名教育行业的创业者,我非常希望能向和我一样热爱算法、热爱编程的你,分享我的经验。所以,在2019年开设了《人人都能学会的编程入门课》之后,时隔一年,我又带来了《常用算法25讲》。

算法到底有多重要,这已经是一个老生常谈的话题了。我相信,你在看这个课程之前,肯定也看过非常多的文章,这些文章都从不同的角度告诉你,为什么要学算法,以及怎么学。但你真的学会了吗?

就像有很多的学生,在和我学习算法之前,会问我这几个问题:

  • 我知道算法很重要,但是工作中好像总也用不到。
  • 我为了面试学算法,刷了那么多题,遇到新题还是不会怎么办?
  • 这么多算法知识,总是学了又忘,忘了又学,怎么才算学会呢?

如果你也有同样的疑问,那说明你真没学好算法。想要学好算法,我们必须要纠正几个误区。

误区一:学算法就是为了面试,工作中根本没用

很多大厂的面试都要考算法,所以很多人学算法,就只是为了面试,他们把算法当成了一种应用技术。这会导致我们在学算法的时候,只关注能不能用某个算法解决某个问题。当解决不了这个问题的时候,算法自然就显得“没用”了。

可我想说,有些知识的学习是面向当下的。例如,我想用命令操作一个服务器,那我学习相关命令的使用就行了,不用去了解操作系统底层。而有些知识的学习,是面向未来的,就像算法学习。

为了更形象地说明这一点,我想给你讲一个建筑工人村头老王的故事。首先,我想问你一个问题,如果我让你盖一个“茅草屋”,你会做些什么准备?你会去学习建筑艺术,还是去学习相关的计算机设计软件,又或者是去了解相关知识?

如果你真的去盖了房子,就会发现这些准备都是无用的。因为即便是村头的“王大爷”,在不了解这些专业知识的情况下,也能用现有的材料,给你盖一个像样的茅草屋。那么问题来了,会盖茅草屋就等于懂建筑吗?当然不是。因为我们重复盖20次茅草屋,也盖不出 20 层楼。所以,知识有没有用,主要是看你要实现的目标是什么

如果你要实现的目标,就是盖一个茅草屋,那么建筑学相关的知识很多都是用不上的,凭感觉盖就行了。而如果你的目标是盖20层的高楼,那你真的需要花很多时间来学习大量的理论知识。理论与实践永远都是相辅相成的,没有理论的实践会丧失高度,没有实践的理论也会变得空洞无用。

编程或者说我们的程序设计之路,就像是去盖这20层高楼,我们必须要学习大量的基础理论知识才能走得更稳,算法就是其中非常重要的基石。

误区二:学数据结构和算法 = 走“弯路”

抛开面试,我们再来谈谈工作。

在 IT 企业中流传着一句老话:大公司造轮子,小公司用轮子。越是大型的互联网公司,自己造的轮子越多。因此,快速掌握行业知识的能力,也是我们必须要具备的核心竞争力。这都是建立在拥有大量专业基础知识之上的。

如果说应用知识标记了你在行业跑道中的距离,基础知识就是你在行业跑道中的加速度。一个加速度大的人,即便他在一开始是落后的,通过几年的发展,最终也会赶上那些起点很高,但速度很慢的人。

可是很多人并不注重基础知识。举个简单的例子,我教过一些学生,他们在最开始学习写代码的时候,就是把代码写出来而已。一旦他们的代码运行出错,就会跑过来问我到底是怎么回事儿。因为他们认为,写代码就是写代码,找代码的错误就是在“走弯路”。可实际上,写代码的目标并不是把代码写出来,而是用代码将逻辑正确地表达出来。只有找到自己代码中的错误,才能使自己的代码能力真正得到增长。

这其实也是我们学习数据结构和算法的意义。换句话说,我们要根据数据的性质,用一套合适的计算流程把它们写到计算机中,然后表达出我们想要的逻辑。

总的来说,我认为,在学习中犯错不是在走弯路,学习基础知识也不是在走弯路,而正是这些所谓的“弯路”才是通往行业核心的真正捷径。所以我说的捷径,其实就是在学习过程中,多给自己一些耐心、努力,找对真正有用的学习方法。这也是我做这门课的初衷。想想我们将来要面对的几十年行业生涯,除了学习应用技术外,多花几个月时间在基础知识的学习上,我觉得一点儿都不多,甚至很划算。

误区三:算法我自己能学,没必要跟老师学

有些同学可能会问,那算法一定要跟着老师学吗?在回答这个问题之前,我想先问你一个事儿:去肯德基点东西的时候,如果多点一个蛋挞会让你这顿饭吃得更满足,你会不会点?我想咱们的答案应该是一样的,肯定会点。

其实肯德基这个例子,就已经回答了最开始的问题,需要跟老师学么?答案就是,不冲突。咱们假设,你现在可选的学习方式有:看技术博客 + 看书学习。那么所谓的跟老师学习,不是剥夺了你看技术博客和看书学习的权利,而是作为你现有学习方法的一种补充。老师的作用,也不是单纯的知识灌输。一个好的老师,最主要的作用,是帮助你抓住学习重点,帮助你规范你的训练方法,帮助你提高学习效率。

所以,跟着老师学习,是对你现有学习方法的补充。如果你自己就能学好,那么跟着一个老师学,肯定会学得更好。只是,你需要选择一个好的老师。尤其是计算机领域的好老师,需要理论和实战两手抓两手硬,这就非常难找。如果你真的碰到了好老师,跟他学,准没错的。

这门课是怎么设计的?

那说了这么多,我们其实还是要落回到怎么学算法这个话题上。我认为,学算法最重要的不是学习这个算法是什么或者刷题目,而是要学习这类算法,具体的设计过程。就像你到了健身房里面,你要做的第一件事情不是马上去举铁,而是要找个健身教练问问每一块肌肉的训练方法,这是我们肌肉训练的框架。

算法训练也是有这种框架的。举个例子,很多同学认为动态规划算法很难学,那是因为他们训练动态规划算法的方式错了。如果他们幻想通过多刷几道题目,就能掌握动态规划算法,就会像进入健身房试图直接举铁的健身小白一样,十有八九都会失败。

设计动态规划算法,一般可以分成三步走:状态定义、推导动归方程和程序编写。其中最难的,就是准确地理解状态定义。可以说,搞定了状态定义,也就搞定了动态规划算法。所以,我们没必要盲目刷题,只需要在解决一道题目的同时,从中不断加强我们对于动态规划三个部分的理解深度就行了。

最后,你一定要记住,学习算法最重要的,是学习算法的设计过程,而不是算法本身

以上这些,其实就是我们课程的核心设计思想。接下来,我就和你说说这门课程是如何设计的。

我希望这门算法课,能带你学习最常用、最实用的算法知识,教给你相关算法的高效学习方法,让你从不懂算法或者不了解算法,到掌握算法,并且拥有自学算法的能力。因此,我特意选择了在实际工作中经常会被用到的三类算法,分别是排序算法、查找算法与搜索算法。我们的课程也因此分为三个部分:排序篇查找搜索篇和进阶篇

排序篇

我会从快速排序算法、快排优化、快速选择算法,讲到堆排序、归并排序,以及由这些排序延伸出来的一些趣味算法。我希望你从中学会的不是单一的算法,而是这些排序算法中所映射出来的思维方式。毕竟,掌握算法思维,才是算法学习的重中之重

基于此,针对每个算法,我会搭配一些经典的面试题,给你详细讲解它能解决的问题、算法流程、优化拓展,以及它所需要的数据结构基础。时间复杂度我也会讲,但因为它涉及非常多的公式推导,所以我不会详细去讲。我的建议是,等你的算法能力掌握到一定程度之后,再学不迟。

除此之外,我还会带你从0到1一起封装一个线程池,让你体会程序设计的全过程。

查找搜索篇

查找部分,我主要会给你讲两种非常重要,也是工作中最常用的数据结构:红黑树与哈希表。学好这两种数据结构,能更好地理解和使用语言中给我们准备好的相关功能模块。

为了让你更好地理解红黑树,我会从最基础的排序二叉树入手,由浅入深带你学习。并且我对于网上现有的红黑树代码做了优化,帮助你大幅度降低了红黑树的编码学习难度,只要你跟着学,我保证这是全网最简单、易学的红黑树教程。

关于哈希表,我会重点带你学习哈希表的映射思想,也就是其中的哈希操作。对于如何设计哈希函数这个哲学问题,我也会跟你深入讨论一下。

搜索算法部分,我也会结合迷宫问题,来讲两种经典,并且非常基础的搜索算法,深度优先搜索广度优先搜索。保证你学起来不枯燥。

进阶篇

我会带你综合运用我们所学的内容,一起来求解数独游戏、2-Sum 问题、计算sqrt。而且,我还会给你分享一种比系统自带的 sqrt 更快的函数。除此之外,我还给你准备了一个有挑战的毕业设计,就是设计一个用 O(1) 时间复杂度计算数字末尾 0 的个数的程序。你可不要小看这个问题,这个问题会用到你在算法课程中学到的全部知识,包括所有的算法及程序设计方面的技巧。做好准备,和我一起做点儿有挑战的事情吧!

最后,我想说,算法学习,就跟你进健身房一样,要学会正确的锻炼方法,还需要不断地训练巩固。这是一个不断挑战你“智力+毅力”的过程,也是算法的价值所在。你需要明白一个道理,算法没有会或者不会一说,只有程度深、浅一说。坚持锻炼算法思维的你,总会比那个曾经的你要更强,那你究竟选择拥抱哪个自己呢?这不是算法难或者简单的问题,而是你自己如何选择的问题。

还等什么?快加入和我一起学算法吧!