算法设计与分析是计算类专业的核心课程,学生在学习该课程时,普遍更容易理解理论,却常常无从下手解决一个实际问题。如何将理论知识应用到实践中解决实际问题?本书从计算思维培养的角度,将算法设计的思想利用通俗易懂的实例进行解释,提供大量实际问题、案例进行分析,希望学生能通过大量的实例分析建立一种有效的思维方式(计算思维),掌握求解问题的思路,进而提高解决实际问题的能力。本书作为计算机专业的核心课程“算法设计与分析”的辅助教材,适用于计算机专业的高年级学生阅读,通过实践案例拓展眼界,提高实践能力。
前言
虽然自己讲授“算法设计与分析”课程很多年了,但是一直没有想过写一本书。去年,应清华大学出版社邀约,萌生了写一本书的想法。为什么讲了这么多年课,直到现在才有写书的想法呢?一个主要原因就是我越来越强烈地感觉到:学生虽然能够理解课堂讲授的理论知识,但是在解决实际问题时,他们似乎难以下手。
为什么会有这种现象呢?我仔细思考之后,找到了一个关键的问题。“算法设计与分析”这门课程的理论是比较抽象的,虽然不难理解,但它就像天上的云一样,不容易落地。那么,如何能让理论知识落地,指引读者去解决实际问题呢?这就好像踢足球,如果只是听别人讲如何踢足球,一般人都能听懂,但是听懂了并不代表自己会了,如果要会踢足球,还需要大量的练习。
对于“算法设计与分析”这门课程而言,掌握理论知识之后也需要大量练习,那么怎样练习呢?就是在实际案例中去应用。但是在应用时需要注意,目标不能仅仅是解决某个问题,而要关注解决这个问题背后的思想方法。举一个简单的例子,假设我们要设计一个效率是O(logn)的算法求xn的值,其中x和n都是已知的。如果仅从解决问题的角度,可以利用n的二进制表达逐位处理,也可以达到O(logn)的效率。但是如果读者想要练习算法设计思想,就要分析这个问题的结构,也就是xn=xn/2×xn/2,从这个结构可以看出,原问题xn和子问题xn/2是一样的,仅仅是问题的规模有所区别,这样就出现了分治法求解的算法设计思路了,即原问题被分解为两个子问题。如果定义函数F(n)=xn,然后简单地利用F(n)=F(n/2)×F(n/2)的思路写代码,就会导致效率达到O(n),而不是O(logn),这个分析过程可以利用递归算法效率分析的方法推导出。这时,我们就能发现这里的核心问题是子问题求解了两次,如果能求解一次子问题,就可以达到O(logn)的算法效率。这样,算法优化的思想就清晰了,我们可以把子问题的解F(n/2)存起来,并通过这个临时变量来计算F(n),而不是调用两次子问题求解,就可以提高算法效率。
上面这个简单的例子说明,算法设计与分析在实践的过程中,我们更需要关注的是如何分析问题的结构,原问题与子问题有什么关系?什么样的算法设计策略适合解决这个问题?又如何通过效率分析进一步优化算法?而不是仅仅关注如何得到这个问题的解。所以,我想在这本书里表达的一个思想就是,希望各位读者在每个案例中关注算法设计的思想如何体现的、算法设计的思路是怎样的。如果能从这些角度去理解书中提供的案例,可能会对各位读者更有帮助。
本书基于Thomas H.Cormen等编写的著名教材《算法导论》中的部分内容,介绍了算法设计的基本策略,例如分治法、贪心法、动态规划等,同时简单介绍了算法效率分析中的渐进效率和摊还分析方法。由于这些内容在原著中都有表述,本书尽量从通俗易懂的角度对算法思想进行了解释,同时增加了回溯法的算法设计方法。本书收集了各种算法设计的案例,并且致力于把这些案例实现的思想解释清楚,让读者在多个案例里不断练习,逐渐建立计算思维的思维方式,从而在遇到一个实际问题时,能有一个下手的思路,通过分析问题的结构去寻找求解问题的方法。
算法设计与分析实践案例解析前言写书实在是一个漫长而痛苦的过程,对于每个案例,我在梳理思路时同样感到吃力。然而,这也是一个快速提升的过程。由于本人能力有限,书中一些算法思想的表达只是个人的一些理解,难免有不准确的地方,请各位读者指正。
本书中的多个案例与求解算法来自GeeksforGeeks官网、斯坦福大学的CS166: Advanced Data Structures课程、杜克大学的CPS 230: Design and Analysis of Algorithms课程、麻省理工学院公开课资源的Advanced Algorithms课程的部分课件,在此表示衷心感谢。
本书由“深圳大学教材建设项目”资助。在本书的撰写过程中,两位参编老师李炎然、吴定明做了很多工作。其中,李炎然老师提供了大量的动态规划案例,这些案例都是李老师自己设计的。吴定明老师在图论方面提供了很多好的资料,拓宽了本书的案例深度和广度。深圳大学计算机与软件学院2021级学生曹婉楠,2022级学生陈恺斌、陈碧晗、黄德海、黄雨欣参与了本书的资料整理,在此表示深深的感谢。同时,感谢深圳大学计算机与软件学院算法设计与分析课程组全体老师的支持!
杨烜
2025年7月
杨烜,教授,博士生导师,深圳大学计算机与软件学院教学副院长,1991年毕业于西安电子科技大学,获学士学位,1994、1998年毕业西安交通大学获硕士、博士学位,1998年至2001年期间在西安电子科技大学博士后流动站工作,2001年至今在深圳大学工作。主持完成科技支撑计划项目课题一项,国家自然科学面上项目三项,作为参研单位主持人完成国家自然科学广东省联合一项,国家重点实验室项目一项,广东省自然科学一项,深圳市科技计划项目多项。获得总参科技进步二等奖一项,陕西省科学技术三等奖一项,陕西高等学校科学技术一等奖一项。深圳市教师,获国家教学成果二等奖一项,广东省教学成果一等奖一项。
目录
配套资源
第1章算法和计算思维1
1.1算法基本概念及效率分析1
1.1.1什么是算法1
1.1.2算法设计的基本过程2
1.1.3算法效率分析的基本方法3
1.2算法与计算思维11
第2章分治法13
2.1分治法概述13
2.2分治法中的计算思维15
2.3分治法的实践案例16
2.3.1求第k个数16
2.3.2粉刷问题21
2.3.3棋盘覆盖问题24
2.3.4数组的反转计数27
2.3.5天际线问题32
2.3.6凸包问题36
第3章回溯法45
3.1回溯法概述45
3.2剪枝48
3.3回溯法与寻优问题49
3.4回溯法与分支界限法50
3.5回溯法中的计算思维51
3.6回溯法的实践案例52
3.6.1数独问题52
3.6.2骑士巡游问题55
3.6.3子集划分问题58
3.6.4括号生成问题61
3.6.5地图填色问题62
3.6.6运算表达式优先级66
第4章动态规划68
4.1动态规划概述68
4.2动态规划中的计算思维71
4.3动态规划的实践案例72
4.3.1最长等差子序列72
4.3.2子系列和最大问题74
4.3.3获益最大问题76
4.3.4图像编码问题80
4.3.5最长不重叠子串问题83
4.3.6粉刷问题85
4.3.7树的最大高度问题87
4.3.8分割等和子集问题92
4.3.9跳跃问题96
4.3.10最长严格递增子序列100
4.3.11回文串划分问题102
4.3.12括号生成问题110
4.3.13作业调度问题112
第5章贪心法115
5.1贪心法概述115
5.2贪心法中的计算思维117
5.3贪心法的实践案例117
5.3.1最少站台问题117
5.3.2最短超级字符串121
5.3.3重排字符串问题124
5.3.4图顶点填色问题127
5.3.5奶茶找零问题129
5.3.6将整数n变成1131
第6章图论算法134
6.1图论基本算法134
6.1.1图的基本概念134
6.1.2图的数据结构表示136
6.1.3广度优先搜索136
6.1.4深度优先搜索138
6.1.5图搜索算法应用140
6.1.6连通性141
6.1.7最小生成树算法145
6.1.8最大流算法149
6.2图论算法应用实例155
6.2.1蛇梯问题155
6.2.2桥问题157
6.2.3查找超级节点162
6.2.4二分图匹配问题165
6.2.5点连通度和边连通度166
6.2.6边不相交问题170
6.2.7环流问题171
6.2.8机场调度问题174
6.2.9项目选择问题178
6.2.10棒球比赛问题180
第7章摊还分析184
7.1摊还分析与渐进分析184
7.1.1栈操作185
7.1.2二进制计数185
7.2聚合分析186
7.2.1栈操作186
7.2.2二进制计数186
7.2.3字典187
7.3核算法188
7.3.1栈操作188
7.3.2二进制计数189
7.3.3动态表189
7.3.4234树190
7.4势能法192
7.4.1栈操作193
7.4.2二进制计数194
7.4.3动态表195
7.4.4234树195
7.4.5笛卡儿树197
参考文献201