每个系列一本前端好书,帮你轻松学重点。
本系列来自上海交通大学硕士,华为高级算法工程师 靳宇栋 的 《Hello,算法》
程序员圈儿有两种怪象:
1、人人称工程师,但少有人能真正担起一项"工程"。
2、掌握算法本是理所应当,实际寥寥无几。
一直以来,算法好像跟前端开发没多少关联,顶多用来应付面试。
本系列要做的,就是同大家一起啃下这块硬骨头,真正理解算法。
算法是什么
算法是什么,没有标准答案。
先看几个实际案例:
查字典
在字典里,每个汉字都对应一个拼音,而字典是按照字母顺序排列的。
查找"ren"的大概过程如下:
- 翻开字典约一半的页数,查看该页的首字母,假设为 j。
- 字母表中r位于j之后,所以排除前半部分,查找范围缩小一半。
- 不断重复前两个步骤 ,直至找到首字母为r的页码。
打扑克
打牌时,每局都需要整理扑克牌,使其从小到大排列。过程大概如下:
- 将扑克牌划分为"有序"和"无序"两部分,并假设初始状态下最左 1 张扑克牌已经有序。
- 从无序部分抽出一张扑克牌,插入有序部分的正确位置。
- 不断重复步骤 2 ,直至所有扑克牌都有序。
找零钱
在超市购买了 69 元的商品,给收银员 100 元,收银员需要找 31 元。大概过程如下:
- 可选项是比 31 元面值更小的货币,包括 1 元、5 元、10 元、20 元。
- 从中拿出最大的 20 元,剩余 31 − 20 = 11 元。
- 从剩余选项中拿出最大的 10 元,还剩 11 − 10 = 1 元。
这三个例子涉及的场景大家都非常熟悉,只是可能没意识到,它们就是算法。
算法就是问题的解决方案,并不一定跟编程相关。
从平常的生活细节,到巧夺天工的技艺,都隐藏着精妙的算法思想。
有个著名公式:程序 = 数据结构 + 算法。
所以不要说你没用过算法,只要在写程序,就在运用算法。
学习的难处
如此说来,理解算法并不难,为什么大家觉得难?原因大致两点:
1、大家所熟知的,只是简单问题的一般解,不一定是最优解,算法学习的目标是寻找最优解。
2、从解决思路到代码表示,需要一个转换过程。
编程中有两道坎:一是从完全不懂到具备编程思维,二是从语法正确到算法精良。
跨过第一道坎,写10行代码和1000行代码没有本质区别;跨过第二道坎,就能摆脱"工具人"属性,真正创造价值。
很多人都有这样的感受,学习算法像是重新学一遍编程,若干新概念扑面而来:冒泡、贪心、递归、动态规划、红黑树、B+树...
你得先理解这些概念,再将概念转换成代码。
理解不难,难的是转换,如果脑子转不过来弯儿,就难以完成转换。
怎么办?有人说刷题,刷题的确是一种受欢迎且看似有效的方法,但只是对自学能力强的人而言,基础薄弱的,可能每次都是从一道题开始,又从一道题结束,就像有些人学英语永远都是"abandon"。
何以解忧
学习这件事,没有毫无争议的"标准答案",只有匹配读者当下认知水平的答案。
我们通常看到的资料和教程,讲师的背景和履历都很强,但稍作了解就知道,段位远高于基础。
它试图降低身段教会我们,但你刚理解了一个简单的问题,觉得自己好像可以,接着就迎来一段100行的代码,大脑马上投降------"谁爱看谁看去吧"。
我们需要的不是"看起来很厉害",是能看懂,大脑可以跟随思考的东西,所以有了本书的选择,以及本系列文章。
本书重点着眼于"如何入门",讲解的内容不一定是最优解,也不能保证学完拿到offer,但可以帮你慢慢找到"吸收"算法的感觉,这样以来,学习的进度条才能往前走,哪怕走得慢一些,只要有动力一直走,早晚能到不是吗?
先来两道开胃菜。
数据结构和算法
数据结构总是和算法同时出现,它们是什么关系?
其实生活中随处可见数据结构。
地铁线路是"图 ",公司组织架构是"树 ",叠在一起的盘子是"栈 ",车站排队进站是"队列"。
你或许想问,这些在JavaScript中都没有,怎么办?
JavaScript中,我们熟悉的数据结构只有"数组"和"对象",但其实数组是一种通用型数据结构,以它为基础,可构造出栈、队列、树等,对象则是散列。
那么多数据结构,怎么区分和记忆?
它们可分为"逻辑结构 "和"存储结构"这两类。
逻辑结构:比如树,逻辑上具有"父--->子"关系。
存储结构:物理上是集中存储,还是分散存储。如:数组、链表。
数据结构是算法的基石,提供了结构化存储的数据和操作数据的方法。
算法是数据结构发挥作用的舞台,数据结构结合算法才能解决特定问题。
但要清楚,二者不是一对一的绑定关系,就像生活中的问题总有不同解。算法通常可以基于不同的数据结构实现,但执行效率可能相差很大,所以,往往对应着更优的选择。
质量评估
研究算法,是为了写出更好的程序,那什么是"好"?
如果把代码比作一匹马,好的算法就是"吃得少,还跑得快"。
当我们运行一段代码,直观感受到的,是快慢,不易察觉的,是内存占用。
那么优劣的评定就可归为两个维度:速度和内存,即"时间 "和"空间"。
有了评定标准,怎么验证呢?不可能带着代码去每一台机器上跑一遍。
这时候,就需要一套与机器和网络都无关的评定方法------"复杂度分析"。
复杂度分析体现算法运行所需的资源与输入数据大小之间的关系。它描述了随着数据大小的增加,算法执行所需时间和空间的增长趋势。
趋势是个很有意思的东西,有三个特点:
1、不精确,但能区分相对优劣。
2、忽略细枝末节,只关注大头。
3、量变引起质变,小于某个值的时候,A比B优,超过之后,可能是B比A优。
同时,时间和空间的利用往往难以共存,需要牺牲一方,成全另一方。
后续的学习过程中,还有很多机会感受它们的魅力。
我们的目标
本系列文章,尝试帮助不那么擅长编程的伙伴消除对算法的排斥和恐惧,培养算法思维,了解常见算法的用途和优势。
这里不得不提本书作者靳宇栋(@krahets) ,富有且慷慨,自身技术过硬的同时,能关注到基础相对薄弱的群体的需求,有耐心和创造力创作出这么好的作品,是为行业一大贡献。
著名物理学家费曼教授曾说:"Knowledge isn't free. You have to pay attention."
书籍和文章可能是免费的,但要掌握它们,你需要付出时间和耐心。
希望大家通过这次旅程,体会到思考的乐趣,在后续的生活和工作中,更从容地解决自己遇到的问题。
本书 Github 已有超 110k star, 官网地址: www.hello-algo.com
不论你使用哪种语言,喜欢什么形式,它都能满足,如果等不及,可以先睹为快~
更多好文第一时间接收,可关注公众号:"前端说书匠"