This commit is contained in:
louzefeng
2024-07-09 18:38:56 +00:00
parent 8bafaef34d
commit bf99793fd0
6071 changed files with 1017944 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
<audio id="audio" title="用户故事 | Jerry银银这一年我的脑海里只有算法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c6/a3/c64486f3859df80dbb7c6158be04e0a3.mp3"></audio>
>
比尔·盖茨曾说过“如果你自以为是一个很好的程序员请去读读Donald E. Knuth的《计算机程序设计艺术》吧……要是你真把它读下来了就毫无疑问可以给我递简历了。”虽然比尔·盖茨推荐的是《计算机程序设计艺术》这本书但是本质却折射出了算法的重要性。
大家好我是Jerry银银购买过算法专栏的同学应该时不时会看到我的留言目前我是一名Android应用开发工程师主要从事移动互联网教育软件的研发坐标上海。
## 我为何要学算法?
细细想来从毕业到现在7年多的时间我的脑海里一直没有停止过思考这样一个问题**技术人究竟能够走多远,技术人的路究竟该如何走下去**?相信很多技术人应该有同样的感受,因为技术的更新迭代实在是太快了,但是我心里明白:**我得为长远做打算,否则,就算换公司、换工作,可能本质也不会有什么改变**。
但是我其实不太清楚自己到底应该往什么地方努力。于是我翻阅了好多书籍搜寻IT领域各种牛人的观点。多方比较之后我终于决定从基础开始从计算机领域最基础、最重要的一门课开始。毫无疑问这门课就是数据结构和算法。
## 我是如何遇见极客时间的?
既然找到了方向,那就开始吧。可是问题来了,从哪儿开始呢?大方向虽然有了,可是具体的实现细节还是得慢慢摸索。大学没怎么学,工作这么多年也没有刻意练习,起初我还真不知道从哪儿开始,只是买了本书,慢慢地啃,也找了一些简单的题目开始做。有过自学经历的同学,应该有同感吧?刚开始连单链表翻转这样简单的题都要折腾半天,真心觉得“痛苦”。
之前我在极客时间上订阅过“Java核心技术36讲”体会到了专栏和书本的不同。极客时间的专栏作者都是有着丰富的一线开发经验能很好地把知识和实战结合在一起的大牛。这些课听起来非常爽。估计你应该经常跟我一样感叹“哦原来这些知识还可以这么使用”当时我就在想极客时间啥时候有一门算法课就好了。
说来真是巧没多久极客时间就推出了“数据结构与算法之美”。我试读了《为什么要学习数据结构和算法》和《数组为什么很多编程语言中数组都从0开始编号》这两篇之后立即购买了。
到现在,专栏学完了,但是我依然记得,王争老师在《为什么要学习数据结构和算法》这篇文章里面提到的三句话,因为这每一句话都刺痛了我的小心脏!
>
<p>第一句业务开发工程师你真的愿意做一辈子CRUD Boy吗<br>
第二句:基础架构研发工程师,写出达到开源水平的框架才是你的目标!<br>
第三句:对编程还有追求?不想被行业淘汰?那就不要只会写凑合能用的代码!</p>
## 我每天是怎么学专栏的?
于是,每天早上醒来,我的第一件事就是听专栏!专栏在每周的一、三、五更新,每周的这三天早上,我会听更新的文章。其它时间,我就听老的文章,当作复习。
听的过程,我一般会分这么几种情况。
**第一种情况,更新的内容是我之前就已经学过的,基本已经掌握了的**。这种情况下,听起来相对轻松点,基本上听一遍就够了。起床之后,再做一下老师给的思考题。这种情况在专栏的基础部分出现得比较多,像数组、链表、栈、队列、哈希表这些章节,我基本上都是这么过来的。
**第二种情况,更新的内容是我学过的,但是还不太精通的**。这种情况下,王争老师讲的内容都会将我的认知往前“推进”一步。顺利的话,我会在上班之前就搞懂今天更新的内容。这种情况是曾经没有接触过的内容,但是整体来说不难的理解的,比如跳表、递归等。
**还有一种情况,就是听一遍不够,听完再看一遍也不行,上午上班之前也搞不定的**。不过,我也不会急躁。我心里知道,我可能需要换换脑子,说不定,在上午工作期间,灵感会突然冒出来。这种情况一般出现在红黑树、字符串查找算法、动态规划这些章节。
到了中午休息时间,我会一个人在公司楼下转一圈,同样,还是听专栏、看专栏。
如果今天的文章,早上已经搞定了,我会重新看下其他同学的留言,看看其他同学是如何思考文章的课后思考题的,还有就是,我会看看其他同学学习过程中,会有哪些疑问,这些疑问自己曾经是否遇到过,现在是否已经完全解决了。
如果今天的文章,早上没有彻底搞懂,这种情况下,我会极力利用中午的时间去思考。
晚上的时间通常无法确定,我有时候会加班到很晚,回到家,再去啃算法,效率也不高。所以,我一般会在晚上“看”算法。为什么我会用双引号呢?是因为我真得只是“看”,目的就是加深印象。
以上基本是我工作日学专栏的“套路”。
等到了周末或者其它节假日,就是“打攻坚战”的时候了。估计很多上班族和我一样,只有周末才有大量集中思考的时间。这时候,我一般会通过做题来反向推动自己的算法学习。
像红黑树、Trie树、递归、动态规划这些内容我都是在周末和节假日搞懂的。虽然到现在对其中一些知识还不能达到游刃有余的地步但是对一般的问题大体上我都知道该如何抽象、如何拆解了。
<img src="https://static001.geekbang.org/resource/image/0c/72/0c441ee9376e974f5112eab4dd7b2672.jpg" alt="">
<img src="https://static001.geekbang.org/resource/image/ef/27/ef0c2d2cbde571905fde6ebf72913a27.jpg" alt="">
## 通过学习专栏,我有什么不一样的收获?
**首先,专栏学习拓宽了我的知识面。**例如,很多书本不讲的跳表,王争老师用了一篇文章来讲解。犹记得当我看完跳表时,心想,这么简单、易懂、高效的数据结构,为什么很多书籍都没有呢?这个专栏真的买值了!
**其次,专栏的理论和实践结合很强。**书籍是通用性很强的教材,一般很少会涉及软件系统是如何使用具体的数据结构和算法的。在专栏中,老师把对应的知识和实践相互结合,听起来特别过瘾!比如堆这种数据结构,理解起来不难,但是要用好它,还得下点功夫,经过老师一讲解,搭配音频,我的理解也变得更加深入了。
**最后,专栏留言这个功能真的太好了,为自学带来了诸多便利,也让我获得了很多正向反馈。**很多时候,经过相当长的一段时间思考,还是不能打通任督二脉,其实后来回想,当时就差那一层窗户纸了。于是,我在文末留下了自己的疑问,结果王争老师轻描淡写一句话我就明白了。
留言功能还有个非常大的好处。如果你用心学习用心思考用心留言你的留言很大概率会被同伴点赞很多时候还能被置顶。这本身就是一种正向反馈也会更加促进自己的学习动力。还有一种更爽的体验突然有一天早上我照例醒来听专栏突然听到了自己的名字。这个专栏4万多人订阅老师居然记得我可见王争老师真的认真看了每一条留言。
最后,我总结下自己学这个专栏的收获。尽管很多,但是我想用三句话来概括。
第一,写代码的时候,我会很自然地从时间和空间角度去衡量代码的优劣,时间、空间意识被加强了很多。
第二,学习算法的过程,有很多的“痛苦”,也正是因为这些“痛苦”,我学到了很多知识以外的东西。
第三,过程可能比知识更重要。要从过程中体会成长和精进的乐趣,而知识是附加产品!
专栏虽然结束,但是学习并没有结束。同学们,我们开头见!

View File

@@ -0,0 +1,97 @@
<audio id="audio" title="用户故事 | zixuan站在思维的高处才有足够的视野和能力欣赏“美”" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/50/e2/5004d60ded8e84f51807b425db15e5e2.mp3"></audio>
大家好我是zixuan在一家国内大型互联网公司做后端开发坐标深圳工作5年多了。今天和大家分享一下我学习专栏的一些心得体会。
随着年龄的增长,我经历了不少业务、技术平台、中间件等多种环境和编程工具的迭代变更。与此同时,我越来越意识到,要做一名优秀的程序员,或者说,能够抵御年龄增长并且增值的程序员,有两样内功是必须持续积累的,那就是**软件工程经验方法**和**算法应用能力**。
通俗地讲,就是不论在什么系统或业务环境下、用什么编程工具,都能写出高质量、可维护、接口化代码的能力,以及分解并给出一个实际问题有效解决方案的能力。
## 我为什么会订阅这个专栏?
这也是为什么我在极客时间上看到王争老师的“数据结构与算法之美”的开篇词之后,果断地加入学习行列。同时,我也抱有以下两点期望。
第一,这个专栏是从工程应用,也就是解决实际问题的角度出发来讲算法的,原理和实践相辅相成,现学现用,并且重视思考过程。从我个人经验来看,这的确是比较科学的学习方法。我相信很多人和我一样,以前在学校里都学过算法,不过一旦不碰书了,又没有了应用场景后,很快就把学过的东西丢了,重新拾起来非常困难。
第二,从专栏的标题看出,王争老师试图带我们感受算法的“美”,那必将要先引导我们站在思维的高处,这样才有足够的视野和能力去欣赏这种“美”。我很好奇他会怎么做,也好奇我能否真正地改变以前的认知,切身地感受到“美”。
## 我是如何学习这个专栏的?
就这样,同时带着笃定和疑问,我上路了。经过几个月的认真学习,“数据结构与算法之美”成了我在极客时间打开次数最多,花费时间最多,完成度也最高的一门课。**尽管如此,我觉得今后我很可能还会再二刷、多刷<strong><strong>这门课**</strong>,把它作为一个深入学习的索引入口。</strong> 接下来,我就从几个方面,跟你分享下,这半年我学习这个专栏的一些感受和收获。
### 1.原理和实用并重:从实践中总结,应用到实践中去
学习的最终目的是为了解决实际问题,专栏里讲的很多方法甚至代码,都能够直接应用到大型项目中去,而不仅仅是简单的原理示例。
比如王争老师在讲散列表的时候讲了实现一个工业级强度的散列表有哪些需要注意的点。基本上面面俱到我在很多标准库里都找到了印证。再比如老师讲的LRU Cache、Bloom Filter、范围索引上的二分查找等等也基本和我之前阅读LevelDB源代码时看到的实现细节如出一辙无非是编程语言的差别。
所以,看这几部分的时候,我觉得十分惊喜,因为我经历过相关的实际应用场景。反过来,专栏这种原理和实用并重的风格,也能帮助我今后在阅读开源代码时提升效率、增进理解。
另外,我觉察到,文章的组织结构,应该也是老师试图传达给我们的“他自己的学习方法”:从开篇介绍一个经典的实际问题开始(需求),到一步步思考引导(分析),再到正式引出相关的数据结构和算法(有效解决方案),再将其应用于开篇问题的解决(实现、测试),最后提出一个课后思考题(泛化、抽象、交流、提升)。
这个形式其实和解决实际工程问题的过程非常类似。我想,大部分工程师就是在一个个这样的过程中不断积累和提升自己的,所以我觉得这个专栏,不论是内容还是形式真的都很赞。
<img src="https://static001.geekbang.org/resource/image/fa/70/fa96a398ed927b9e6c4dabcdb7bb1370.jpg" alt="">
### 2. 学习新知识的角度:体系、全面、严谨、精炼,可视化配图易于理解
“全面”并不是指所有细节面面俱到。事实上由于算法这门学科本身庞大的体量这类专栏一般只能看作一个丰富的综述目录或者深入学习的入口。尽管如此王争老师依然用简洁精炼的语言Cover到了几乎所有最主要的数据结构和算法以及它们背后的本质思想、原理和应用场景知识体系结构全面完整并自成一体。
我发现只要能紧跟老师的思路,把每一节的内容理解透彻,到了语言实现部分,往往变成了一种自然的总结描述,所以代码本身并不是重点,重点是背后的思路。
例如KMP单模式串匹配和AC自动机多模式串匹配算法是我的知识盲区。以前读过几次KMP的代码都没完全搞懂于是就放弃了。至于AC自动机惭愧地说我压根儿就没怎么听说过。
但是在专栏里王争老师从BruteForce方法讲起经过系统的优化思路铺垫通俗的举例再结合恰到好处的配图最后给出精简的代码。我跟随着老师一路坚持下来当我看到第二遍时突然就豁然开朗了。而当我真正理解了AC自动机的构建和工作原理之后在某一瞬间我的内心的确生出了一种美的感觉或者更多的是“妙”吧
AC自动机构建的代码让我不自觉地想到“编织”这个词。之前还觉得凌乱的、四处喷洒的指针在这里一下子变成了一张有意义的网编织的过程和成品都体现出了算法的巧妙。这类联想无疑加深了我对这类算法的理解也许这也意味着我可以把它正式加入到自己的算法工具箱里了。
另外一个例子是动态规划。以前应用DP的时候我常常比较盲目不知道怎么确定状态的表示甚至需要几维的状态都不清楚可以说是在瞎猜碰运气。经过老师从原理到实例的系统讲解后我现在明白原来DP本质上就是在压缩重复子问题状态的定义可以通过最直接的回溯搜索来启发确定。明白这些之后动态规划也被我轻松拿下了。
### 3. 已有知识加深的角度:促进思考,连点成线
之前看目录的时候,我发现专栏里包含了不少我已经知道的知识。但真正学习了之后,我发现,以前头脑中的不少概念知识点,是相对独立存在的,基本上一个点就对应固定的那几个场景,而在专栏里,王争老师比较注重概念之间的相互关联。对于这些知识,经过王争老师的讲解,基本可以达到交叉强化理解,甚至温故知新的效果。
比如老师会问你在链表上怎么做二分查找哈希和链表为什么经常在一起出现这些问题我之前很少会考虑到但是当我看到的时候却启发出很多新的要点和场景比如SkipList、LRUCache
更重要的是,跟着专栏学习一段时间之后,我脑中原本的一些旧概念,也开始自发地建立起新的连接,连点成线,最后产生了一些我之前从未注意到的想法。
举个感触最深的例子。在跟随专栏做了大量递归状态跟进推演,以及递归树分析后,我现在深刻地认识到,递归这种编程技巧背后,其实是树和堆栈这两种看似关联不大的数据结构。为什么这么说呢?
堆栈和树在某个层面上其实有着强烈的对应关系。我刚接触递归的时候和大多数初学者一样脑子很容易跟着机器执行的顺序往深里绕就像Debug一个很深的函数调用链一样每遇到一个函数就step into也就是递归函数展开-&gt;下一层-&gt;递归函数展开-&gt;下一层-&gt;…,结果就是只有“递”,没有“归”,大脑连一次完整调用的一半都跑不完(或者跑完一次很辛苦),自然就会觉得无法分析。如下图,每个圈代表在某一层执行的递归函数,向下的箭头代表调用并进入下一层。
<img src="https://static001.geekbang.org/resource/image/24/d2/24358b72ff5db99b0dc837b0c81fb4d2.jpg" alt="">
随着我处理了越来越多的递归我慢慢意识到为什么人的思考一定要follow机器的执行呢在递归函数体中我完全可以不用每遇到递归调用都展开并进入下一层step into而是可以直接假定下一层调用能够正确返回然后我该干嘛就继续干嘛step over这样的话我只需要保证最深一层的逻辑也就是递归的终止条件正确即可。
原因也很简单不管在哪一层都是在执行递归函数这同一份代码不同的层只有一些状态数据不同而已所以我只需要保证递归函数代码逻辑的正确性就确保了运行时任意一层的结果正确性。像这样说服自己可以随时step over后我的大脑终于有“递”也有“归”了后续事务也就能够推动了。
<img src="https://static001.geekbang.org/resource/image/5d/f8/5d42370f6823b1ed97d5d86d773ac0f8.jpg" alt="">
最近在学习这门课程的过程中,我进一步认识到,其实上面两个理解递归的方式,分别对应递归树的深度遍历和广度遍历。尽管机器只能按照深度优先的方式执行递归代码,但人写递归代码的时候更适合用广度的思考方式。当我在实现一个递归函数的时候,其实就是在确定这棵树的整体形状:什么时候终止,什么条件下生出子树,也就是说我实际上是在编程实现一棵树。
那递归树和堆栈又有什么关系呢?递归树中从根节点到树中任意节点的路径,都对应着某个时刻的函数调用链组成的堆栈。递归越深的节点越靠近栈顶,也越早返回。因而我们可以说,递归的背后是一棵树,递归的执行过程,就是在这棵树上做深度遍历的过程,每次进入下一层(“递”)就是压栈,每次退出当前层(“归”)就是出栈。所有的入栈、出栈形成的脉络就组成了递归树的形态。递归树是静态逻辑背景,而当前活跃堆栈是当前动态运行前景。
<img src="https://static001.geekbang.org/resource/image/6f/92/6fece59ed3d40f4ba544ec84a12b8092.jpg" alt="">
这样理解之后,编写或阅读递归代码的时候,我真的能够站得更高,看得更全面,也更不容易掉入一些细节陷阱里去了。
说到这里我想起之前在不同时间做过的两道题一道是计算某个长度为n的入栈序列可以有多少种出栈序列另一道是计算包含n个节点的二叉树有多少种形状。我惊讶地发现这两个量竟然是相等的其实就是卡特兰数。当时我并不理解为什么栈和树会存在这种关联现在通过类似递归树的思路我觉得我能够理解了那就是每种二叉树形状的中序遍历都能够对应上一种出栈顺序。
类似这样“旧知识新理解”还有很多,尽管专栏里并没有直接提到,但是这都是我跟随专栏,坚持边学边思考,逐步感受和收获的。
## 总结
基于以上谈的几点收获和感受,我再总结下我认为比较有用的、学习这个专栏的方法。
**1.紧跟老师思路走,尽量理解每一句话、每一幅配图,亲手推演每一个例子。**
王争老师语言精炼。有些文字段落虽短,但背后的信息量却很大。为了方便我们理解,老师用了大量的例子和配图来讲解。即便是非常复杂、枯燥的理论知识,我们理解起来也不会太吃力。
当然有些地方确实有点儿难,这时我们可以退而求其次,“先保接口,再求实现”。例如,红黑树保持平衡的具体策略实现,我跟不下来,就暂时跳过去了,但是我只要知道,它是一种动态数据的高效平衡树,就不妨碍我先使用这个工具,之后再慢慢理解。
**2.在学的过程中回顾和刷新老知识点,并往工程实践上靠。学以致用是最高效的方法**
**3.多思考,思考比结果重要;多交流,亲身感受和其他同学一起交流帮助很大。**
最后,感谢王争老师和极客时间,让我在这个专栏里有了不少新收获。祝王争老师事业蒸蒸日上,继续开创新品,也希望极客时间能够联合更多的大牛老师,开发出更多严谨又实用的精品课程!