而我也被这一魔力所吸引。
十年前我开始学习算法,并且开始写与算法相关的博客。当时写算法博客的人还不多,网上能搜索到的算法文章也有限。
很多人没有写博客的习惯,因为写博客在一定程度上确实“耽误时间”。
不过当时我只是想记录下来,想着以后如果把这些知识都忘了,至少博客可以证明:曾经我掌握过。
没想到,算法陪伴我一晃就是十年,从本科到研究生,从一家公司到另一家公司,再到算法图书的出版……我的每一段人生经历都在从不同的角度和算法打交道。
随着多年学习和实践,我在各种在线判题平台上积累了上千题,对算法的理解已经有了一套独特的体系。
同时我也发现,很多读者在刷题和学习算法时,真正的苦恼在于没有一套行之有效的刷题顺序。
例如,动态规划是公认的程序员面试里最难掌握的算法,也是出现频率最高的算法。如果仅仅讲解几道题目,即使再举一反三也远远达不到真正理解的程度。如果把动态规划的题目单纯地堆砌在一起,也只会让人越学越懵,陷入“一看就会,一写就废”的怪圈。讲清楚一两道题容易,但把整个动态规划的各个分支讲清楚,把每道题目讲透彻,并用一套方法论来指导就有难度了。这既是我无数日夜伏案思考、反复推理,要帮助读者解决的问题,也是本书的使命所在。
对于二叉树、回溯算法、动态规划等重点数据结构与算法,本书都总结了一套行之有效的方法论,系统性地解决这些算法的相关问题,并把相关题目按照由易到难的顺序编排,让读者循序渐进地征服算法的一座又一座高山。
本书特色
刚开始学习数据结构与算法,或者在力扣(LeetCode)上刷题的读者都有这种困惑——从何学起,先学什么,再学什么。很多人刷题的效率低,主要体现在以下三点:
— 难以寻找适合自己的题目。
— 找到了不合适现阶段做的题目,结果发现毫无头绪。
— 没有全套的优质题解可以参考。
我相信很多读者对此深有体会,所以我将每一个专题中的题目按照由易到难的顺序进行编排,每一道题目所涉及的知识都会有相应的题目做知识铺垫,做到环环相扣。
建议读者按章节顺序阅读本书,在阅读的过程中会发现题目编排上的良苦用心。
本书不仅在题目编排上精心设计,而且在针对读者最头痛的算法问题上做了详细且深入的讲解。
关于动态规划,都知道递推公式的重要性,但dp数组的含义、dp数组的初始化、遍历顺序,以及如何打印dp数组来排查Bug,这些都很重要。例如,解决背包问题时,遍历顺序才是最关键的,也是最难理解的。
关于回溯算法,题目要求集合之间不可重复,那么就需要去重。虽然各种资料都说要去重,但没有说清楚是“树层去重”还是“树枝去重”——这是我为了说明去重的过程而创造的两个词汇。
关于KMP算法,都知道使用前缀表进行回退,可什么是前缀表,为什么一定要使用前缀表,根据前缀表进行回退有几种方式,这些却没有说清楚,导致大家看得一头雾水。
关于二叉树,不同的遍历顺序的递归函数究竟如何安排,递归函数什么时候需要返回值,什么时候不用返回值,什么情况下分别使用前、中、后序遍历,如何实现迭代法,这些都决定了对二叉树的理解是否到位。
本书我同时针对每一个专题的特点,整理出其通用的解法套路。例如,在二叉树专题中,总结了递归“三部曲”来帮助读者掌握二叉树中各种遍历方式的写法。回溯算法中的回溯“三部曲”可以帮助读者理解回溯算法晦涩难懂的过程。动态规划中的动规“五部曲”可以帮助读者在一套思考框架下解决动态规划题目。
相信读者耐心看完本书,会对书中介绍的算法有更深层次的理解。
本书配套资源
本书统一使用C++语言进行讲解,对于使用其他语言的读者,支持Java、Python、Go、JavaScript等多语言版本,同时一些题目还有动画演示,帮助读者更好地掌握本书内容。
致谢
这里要感谢录友们,是你们的支持,让“代码随想录”从无到有,到最后出版成书与读者见面。虽然从未谋面,但通过文字,我们已经交流了整整一年有余。真心地感谢每一位录友。
感谢电子工业出版社的工作人员,特别是陈晓猛编辑。陈编辑工作认真负责,是非常可靠的合作伙伴。
最后我要感谢我的父母——孙世忠先生和马丽丽女士。父母在我求学的路上给予了我最大的支持,付出了非常多。我无以为谢,谨以此书献给他们。
孙秀洋(@程序员Carl)
2021年10月11日于深圳南山