还不懂这八大算法思想,刷再多题也白搭!最优化遍历

算法和数据结构一直以来都是程序员的基本内功,可以说没有数据结构的基础建设和算法加持,也就没有这将近八十年的信息革命时代。数据结构可以看作是算法实现的容器,通过一系列特殊结构的数据集合,能够将算法更为高效而可靠地执行起来。

算法的应用不单只体现在编程中。狭义的来讲,算法可看作是数据传递和处理的顺序、方法和组成方式,就像是各种排序算法等。而广义的来讲,算法更像是一种事物运行的逻辑和规则。太阳东升西落,海水潮汐潮流,月儿阴晴圆缺,这些或许都可以看似一种算法,只不过执行者不是电子计算机,而是自然万物。

聊远了。所以对于算法的理解,重要的是领悟其思想,感受其内在。有同学或许就会说了,「算法不就是Leetcode,不就是刷题嘛」。

片面了啊。题总是刷不完的,但是算法的思想就那么几个。所以呢,刷了那么多题的你,还不了解这几个常见的算法思想,想必是应该好好反省反省下了。

枚举

首先,最为简单的思想,枚举算法。枚举也叫穷举,顾名思义,就是穷尽列举。枚举思想的应用场景十分广泛,也非常容易理解。简单来说,枚举就是将问题的可能解依次列举出来,然后一一带入问题检验,从而从一系列可能解中获得能够解决问题的精确解。

枚举虽然看起来简单,但是其实还是有一些容易被人忽视的考虑点。比方说待解决问题的「可能解/候选解」的筛选条件,「可能解」之间相互的影响,穷举「可能解」的代价,「可能解」的穷举方式等等。

很多时候实际上不必去追求高大上的复杂算法结构,反而大道至简,采用枚举法就能够很好的规避系统复杂性带来的冗余,同时或许在一定程度上还能够对空间进行缩减。

枚举思想的流程可以用下图来表示。通过实现事先确定好「可能解」,然后逐一在系统中进行验证,根据验证结果来对「可能解」进行分析和论证。这是一种很明显的结果导向型的思想,简单粗暴地试图从最终结果反向分析「可能解」的可行性。

不过,枚举思想的劣势当然也很明显。在实际的运行程序中,能够直接通过枚举方法进行求解的问题少之又少。而当「可能解」的筛选条件不清晰,导致「可能解」的数量和范围无法准确判断时,枚举就失去了意义。

然而当「可能解」的规模比较小,同时依次验证的过程容易实施时,枚举思想不失为一种方便快捷的方式。只不过在具体使用时,还可以针对应用场景对「可能解」的验证进行优化。

这种优化可以从两个方向入手,一是问题的简化,尽可能对需要处理的问题进行模型结构上的精简。这种精简具体可体现在问题中的变量数目,减少变量的数据,从而能够从根本上降低「可能解」的组合。

二是对筛选「可能解」的范围和条件进行严格判断,尽可能的剔除大部分无效的「可能解」。

案例

百钱买百鸡问题。该问题叙述如下:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?

翻译过来,意思是公鸡一个五块钱,母鸡一个三块钱,小鸡三个一块钱,现在要用一百块钱买一百只鸡,问公鸡、母鸡、小鸡各多少只?

递推

递推思想跟枚举思想一样,都是接近人类思维方式的思想,甚至在实际生活具有比枚举思想更多的应用场景。人脑在遇到未知的问题时,大多数人第一直觉都会从积累的「先验知识」出发,试图从「已知」推导「未知」,从而解决问题,说服自己。

事实上,这就是一种递推的算法思想。递推思想的核心就是从已知条件出发,逐步推算出问题的解。实现方式很像是初高中时我们的数学考卷上一连串的「因为」「所以」。那个时候还是用三个点来表示的。

而对于计算机而言,复杂的推导其实很难实现。计算机擅长的是执行高密度重复性高的工作,对于随机性高变化多端的问题反而不好计算。相比之下,人脑在对不同维度的问题进行推导时具有更高的自由度。

我说这个例子的用意是在说明,计算机在运用递推思想时,大多都是重复性的推理。比方说,从「今天是1号」推出「明天是2号」。这种推理的结构十分类似,往往可以通过继而往复的推理就可以得到最终的解。

递推思想用图解来表示可以参见下图。每一次推导的结果可以作为下一次推导的的开始,这似乎跟迭代、递归的思想有点类似,不过递推的范畴要更广一些。

兔子问题。定一对大兔子每月能生一对小兔子,且每对新生的小兔子经过一个月可以长成一对大兔子,具备繁殖能力,如果不发生死亡,且每次均生下一雌一雄,问一年后共有多少对兔子?

递归

说完递推,就不得不说说它的兄弟思想——递归算法。二者同样都带有一个「递」字,可以看出二者还是具有一定的相似性的。「递」的理解可以是逐次、逐步。在递推中,是逐次对问题进行推导直到获得最终解。而在递归中,则是逐次回归迭代,直到跳出回归。

递归算法实际上是把问题转化成规模更小的同类子问题,先解决子问题,再通过相同的求解过程逐步解决更高层次的问题,最终获得最终的解。所以相较于递推而言,递归算法的范畴更小,要求子问题跟父问题的结构相同。而递推思想从概念上并没有这样的约束。

用一句话来形容递归算法的实现,就是在函数或者子过程的内部,直接或间接的调用自己算法。所以在实现的过程中,最重要的是确定递归过程终止的条件,也就是迭代过程跳出的条件判断。否则,程序会在自我调用中无限循环,最终导致内存溢出而崩溃。

递归算法的图解可如下图。很明显,递归思想其实就是一个套娃过程。一般官方都是严禁套娃行为的。所以在使用时一定要明确「套娃」举动的停止条件,及时止损。

汉诺塔问题。源于印度传说中,大梵天创造世界时造了三根金钢石柱子,其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

分治

分治,分而治之。

分治算法的核心步骤就是两步,一是分,二是治。但这还引申出了一系列的问题,为什么分,怎么分,怎么治,治后如何。

分治算法很像是一种向下管理的思想,从最高级层层划分,将子任务划分给不同的子模块,进而可以进行大问题的拆分,对系统问题的粒度进行细化,寻求最底层的最基本的解。这样的思路在很多领域都有运用,比如几何数学中的正交坐标、单位坐标、基的概念等,都是通过将复杂问题简化为基本的子问题,然后通过先解决子模块再逐步解决主模块。

在实际的运用中,分治算法主要包括两个维度的处理,一是自顶向下,将主要问题划分逐层级划分为子问题;二是自底向上,将子问题的解逐层递增融入主问题的求解中。

那为什么要分?这个很好解释,由于主要问题的规模过大,无法直接求解,所以需要对主要问题进行粒度划分。

那怎么分?遵循计算机的最擅长的重复运算,划分出来的子问题需要相互独立并且与原问题结构特征相同,这样能够保证解决子问题后,主问题也就能够顺势而解。

怎么治?这就涉及到最基本子问题的求解,我们约定最小的子问题是能够轻易得到解决的,这样的子问题划分才具有意义,所以在治的环节就是需要对最基本子问题的简易求解。

之后如何?子问题的求解是为了主问题而服务的。当最基本的子问题得到解后,需要层层向上递增,逐步获得更高层次问题的解,直到获得原问题的最终解。

分治思想的图解可见下图。通过层层粒度上的划分,将原问题划分为最小的子问题,然后再向上依次得到更高粒度的解。从上而下,再从下而上。先分解,再求解,再合并。

归并排序。

动态规划

讲完分治,我们知道分治思想最重要的一点是分解出的子问题是相互独立且结构特征相同的。这一点并不是所有问题都能满足,许多问题的划分的子问题往往都是相互重叠且互相影响的,那么就很难使用分治算法进行有效而又干净的子问题划分。

于是乎,动态规划来了。动态规划同样需要将问题划分为多个子问题,但是子问题之间往往不是互相独立的。当前子问题的解看作是前多个阶段问题的完整总结。因此这就需要在在子问题求解的过程中进行多阶段的决策,同时当前阶段之前的决策都能够构成一种最优的子结构。这就是所谓的最优化原理。

最优化原理,一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。同时,这样的最优策略是针对有已作出决策的总结,对后来的决策没有直接影响,只能借用目前最优策略的状态数据。这也被称之为无后效性。

动态规划是在目前看来非常不接近人类思维方式一种算法,主要原因是在于人脑在演算的过程中很难对每一次决策的结果进行记忆。动态规划在实际的操作中,往往需要额外的空间对每个阶段的状态数据进行保存,以便下次决策的使用。

动态规划的求解思路如下图解。动归的开始需要将问题按照一定顺序划分为各个阶段,然后确定每个阶段的状态,如图中节点的F0等。然后重点是根据决策的方法来确定状态转移方程。也就是需要根据当前阶段的状态确定下一阶段的状态。

在这个过程中,下一状态的确定往往需要参考之前的状态。因此需要在每一次状态转移的过程中将当前的状态变量进行记录,方便之后的查找。

动态规划主要就是用来解决多阶段决策的问题,但是实际问题中往往很难有统一的处理方法,必须结合问题的特点来进行算法的设计,这也是这种算法很难真正掌握的原因。

背包问题。有n件物品和容量为m的背包,给出物品的重量以及价值。求解让装入背包的物品重量不超过背包容量且价值最大。

贪心

贪心算法,我愿称之为最现实的算法思想。

人活在世上,不可能每一个选择都那么恰到好处。那么多的问题,不可能所有问题都能找到最优解。很多问题根本没有准确解,甚至于无解。所以在某些场景下,傻傻的去追求问题的最精确解是没有意义的。

有人说,那还有最优解呢。难道最优解都不要了吗?

没错,许多问题虽然找不到最精确的解,但是的确会存在一个或者一些最优解。但是一定要去追求这些最优解吗?我看不一定。

算法的存在不是单纯的为了对问题求解,更多的是提供一种「策略」。何谓「策略」,解决问题的一种方式,一个角度,一条路。所以,贪心思想是有价值的。

说回贪心算法。从贪心二字就可得知,这个算法的目的就是为了「贪图更多」。但是这种贪心是「目光短浅」的,这就导致贪心算法无法从长远出发,只看重眼前的利益。

具体点说,贪心算法在执行的过程中,每一次都会选择最大的收益,但是总收益却不一定最大。所以这样傻白甜的思路带来的好处就是选择简单,不需要纠结,不需要考虑未来。

贪心算法的实现过程就是从问题的一个初始解出发,每一次都作出「当前最优」的选择,直至遇到局部极值点。贪心所带来的局限性很明显,就是无法保证最后的解是最优的,很容易陷入局部最优的情况。

但是它每一次做选择的速度很快,同时判断条件简单,能够比较快速的给出一种差不多的解决方案。这里的图解我用下图来表示。

这个图表示的是求解对多条直线的交点。很显然,下图中的直线是不存在统一交点的,但是可以通过算法求得统一交点的最优解。若是采用贪心算法,那么在进行迭代时,每一次都会选择离此时位置最近的直线进行更新。这样一来,在经过多次迭代后,交点的位置就会在某一片区域无限轮回跳转。而这片区域也就是能求得出的大致的最优解区域。

旅行推销员问题。给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。

回溯

蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。

每每提及回溯,都会忍不住想到「蒹葭」里的这句诗。看到心中所怀念的心上人啊,忍不住逆流而上去追寻她,尽管追随的道路险阻又漫长;又顺流而下继续寻觅,感觉她似乎就在河水中央。回溯算法的过程正如追逐爱情般的艰辛和反复,时而溯洄从之,时而溯游从之。

回溯算法也可称作试探算法,是不是让你回忆起了在女神面前的小心翼翼。简单来说,回溯的过程就是在做出下一步选择之前,先对每一种可能进行试探;只有当可能性存在时才会向前迈进,倘若所有选择都不可能,那么则向后退回原来的位置,重新选择。

这样看起来,回溯算法很像是一种进行中的枚举算法,在行进的过程中对所有可能性进行枚举并判断。常用的应用场景就在对树结构、图结构以及棋盘落子的遍历上。

举一个很简单的例子,看下面图解。假设目的是从最O0到达O4,需要对所有节点进行回溯遍历路径。那么回溯算法的过程则需要在前进的每一步对所有可能的路径进行试探。

比方说,O0节点前进的路径有三条,分别是上中下条的O1。回溯过程的开始,先走上面的O1,然后能够到达上面O2,但是这时是一条死路。那么就需要从O2退回到O1,而此时O1的唯一选择也走不通,所以还需要从O1退回到O0。然后继续试探中间的O1。

回溯算法的过程就是不断进行这样的试探、判断、退回并重新试探,直至找到一条完整的前进路径。只不过在这个过程中,可以通过「剪枝」等限制条件降低试探搜索的空间,从而避免重复无效的试探。比方说上下的O2节点,在经过O0-O1-O2的试探之后,就已经验证了该节点不可行性,下次就无须从O1开始重复对O2的试探。

回溯思想在许多大规模的问题的求解上都能得到有效的运用。回溯能够将复杂问题进行分步调整,从而在中间的过程中可对所有可能运用枚举思想进行遍历。这样往往能够清的看到问题解决的层次,从而可以帮助更好地理解问题的最终解结构。

八皇后问题。在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

模拟

模拟思想的理解相比上述思想应该不是什么难事。

许多真实场景下,由于问题规模过大,变量过多等因素,很难将具体的问题抽象出来,也就无法针对抽象问题的特征来进行算法的设计。这个时候,模拟思想或许是最佳的解题策略。

模拟的过程就是对真实场景尽可能的模拟,然后通过计算机强大的计算能力对结果进行预测。这相较于上述的算法是一种更为宏大的思想。在进行现实场景的模拟中,可能系统部件的实现都需要上述几个算法思想的参与。

模拟说起来是一种很玄幻的思想,没有具体的实现思路,也没有具体的优化策略。只能说,具体问题具体分析。

那应该怎么样来图解呢。我的理解是自定义的,任意的输入,不规则的系统响应,但是只为了获得一个可靠的理想的输出。

总结

算法思想这种东西,实际上是很玄幻的。同一种问题,或许在实现上可以采用不同的思想进行。这八种思想也不是想象中那么高的独立性,很多思想都是杂糅在一起的,只是角度和侧重点不同。上面这些案例也不代表只能用一种思想来解答,只是用来体会一下对应的算法思想。

作为底层的程序员,虽说不需要每天刷题,但是基础的算法思想还是需要有的。这种东西不是具体于某个算法,而是在于更高层次的对于系统或者需求的理解。

THE END
1.算法设计非常复杂,如何才能设计出优秀的算法?10.学习和分享:不断学习新的算法技术和数据结构,并积极参与算法社区,分享你的经验和知识。 总之,设计出优秀的算法需要深刻的理解问题、熟练掌握数据结构和算法分析,以及不断的实践和反思。同时,与其他算法设计者和研究者保持沟通,分享经验,共同推动算法设计的进步。 这道题要求讨论如何设计出优秀的算法。算法设计是https://easylearn.baidu.com/edu-page/tiangong/questiondetail?id=1813192804582657431&fr=search
2.算法设计与分析(第3版)课后答案《算法设计与分析》是计算机科学领域的一本经典教材,主要涵盖了如何设计高效算法以及如何对这些算法进行分析。在本书的第三版中,作者王晓东深入浅出地讲解了算法设计的基础理论和实践技巧,并提供了详尽的习题解析,帮助读者巩固所学知识。以下是基于这个主题和提供的文件名“算法设计与分析习题答案”所涵盖的一些关键知识https://download.csdn.net/download/dyufei/1498280
3.趣学算法(第2版)本书实例丰富、通俗易懂,以大量图解展示算法的求解过程,重点讲解遇到实际问题如何分析和设计算法,讲解方式富有启发性,有利于激发学生的学习兴趣和创新潜能。书中汇集了作者根据多年教学实践总结出的各种算法的解题技巧并对知识进行了优化拓展。读者阅读时既能掌握解题的方法,又拓宽了视野,有利于培养其逻辑思维能力,为解决https://www.epubit.com/bookDetails?id=UB7d85fa69dcbd8
4.腾讯Offer已拿,这99道算法高频面试题别漏了,80%都败在算法上3. 如何对类别变量进行独热编码? 4. 如何把“年龄”字段按照我们的阈值分段? 5. 如何根据变量相关性画出热力图? 6. 如何把分布修正为类正态分布? 7. 怎么简单使用PCA来划分数据且可视化呢? 8. 怎么简单使用LDA来划分数据且可视化呢? 深度学习类: https://maimai.cn/article/detail?fid=1699482551&efid=WqEcULyCOsAoPWgBSGGaFg
5.2021届计算机科学方向毕业设计(论文)阶段性汇报在这其中所遇到的挑战有如何支持多种的语义表征任务,如何对每个实体动态的弹出实体创建菜单,以及一些网页格式问题等。 万梓煜 多智能体强化学习的实现 本次阶段性汇报主要介绍多智能体强化学习框架MALib的设计与完成情况,以及针对目前的研究内容实现的功能。其次介绍在当前框架上部分强化学习算法的复现情况以及遇到的https://zhiyuan.sjtu.edu.cn/html/zhiyuan/announcement_view.php?id=3943
6.人工智能快速发展趋势下,中国该如何应对?1、AI芯片针对机器学习算法设计开发,广泛应用于云、边、端各类场景 AI芯片(AI Chip)是一种专门用于处理人工智能相关的计算任务的芯片。它的架构是专门为人工智能算法和应用进行优化的,能够高效地处理大量结构化和非结构化数据。AI芯片能够高效地支持视觉、语音、自然语言处理等智能处理任务。目前,AI芯片主要分为GPU、https://developer.aliyun.com/article/1179745
7.路径规划中的DRL与OR算法:对比与展望引入机器学习的期望之一就是提高其泛化能力,即训练完的模型可以有效地应用于未曾见过的问题实例。为了提高泛化能力,对于图这种非欧几里得数据来说,通过图嵌入(Graph embedding)来抽取数据中的有效特征,通过低维的向量来表征图的节点及拓扑结构等信息,再作为后面机器学习算法的输入。而图神经网络(Graph neural network,GNNhttps://www.51cto.com/article/757803.html
8.《面向算法设计的数据结构》之前世今生算法应用 我们考虑展示更多数据结构在算法中的应用, 特别是引入高效数据结构之后算法性能发生显著变化的实例. 只有通过这些实实在在的例子, 才能让学习者感受到数据结构之妙. 事实上, 写作本书的目的也是为了配合后续进阶算法课程的需要, 希望能让这本书成为学习《算法导论》和《算法设计》的一个良好铺垫, 能让大家https://www.jianshu.com/p/25887f595ca4
9.Creator面对面几何深度学习的算法设计和数学理论机器之心Creator 面对面 | 几何深度学习的算法设计和数学理论 2016年,Yann LeCun 等人在 《Geometric deep learning: going beyond Euclidean data》一文中提出几何深度学习这一概念。现今几何机器学习和基于图的机器学习已经是当前最热门的研究课题之一。 2022 年 1 月,上海交通大学自然科学研究院、数学科学学院副教授王宇光https://www.jiqizhixin.com/articles/2022-07-20-7
10.《自然》:科学家首次基于深度学习算法,从头设计出自然界不存在的酶虽然蛋白结构预测方面有了RoseTTAFold、AlphaFold 2等人工智能算法的相助,但要想实现从头设计全新蛋白质,仍然是个费时费力的艰巨任务。目前,即使是借助机器学习算法,蛋白质设计也主要是把自然界中现有的蛋白质拿来改造,以进行优化或获得特定功能,而非真正地设计并创造一个全新的蛋白质。 https://www.thepaper.cn/newsDetail_forward_22260238
11.第6课《猜数字算法设计》(学案)六年级上册信息科技浙教版.pdf第6课《猜数字算法设计》(学案)六年级上册信息科技浙教版.pdf,六年级第一单元第 6 课《猜数字算法设计》学案 一、学习内容 《猜数字算法设计》选自浙江教育2023 版信息科技六年级上册第一单元第 6 课。通过本单元 的学习,本节课旨在让学生分析猜数字大小的问题,提取关键https://m.book118.com/html/2023/0929/5210031034010334.shtm
12.基于深度强化学习的水面无人艇路径跟踪方法因此,如何设计一种能够提高无人艇路径跟踪控制稳定性和准确性的方法是亟需解决的技术问题。 技术实现要素: 6.针对上述现有技术的不足,本发明所要解决的技术问题是:如何提供一种基于深度强化学习的水面无人艇路径跟踪方法,无需进行环境和无人艇运动建模并且具备自适应能力,从而能够进一步提高无人艇路径跟踪控制的稳定https://www.xjishu.com/zhuanli/54/202210772926.html/
13.AAAI2020强化学习玩王者荣耀腾讯云开发者社区算法设计 Reinforcement Learning用的还是熟悉的actor-critic网络,具体如下图所示: 状态设计:如上图;将图像特征fi,向量特征fu和游戏状态信息fg(可观察到的游戏状态)分别通过卷积层、最大池化层和全连接层编码。LSTM输出动作按钮和移动方向。 动作解耦:认为动作之间独立,目标为最终几个策略累积奖励之和; https://cloud.tencent.com/developer/article/2119379
14.科学网—[转载]基于容器云技术的典型遥感智能解译算法集成模型开发根据预先设计的深度学习算法,基于深度学习框架,进行智能解译算法的代码编写和镜像构建。其基本流程如图8所示,具体如下。 图8 模型开发流程 (1)从私有仓库或开源仓库使用Docker pull操作获取所需的基础环境镜像。基于基础环境镜像,添加OpenCV、GDAL、SciPy等Python包。对基础镜像统一设置SSH登录端口,以便后期调试https://blog.sciencenet.cn/blog-3472670-1339282.html
15.AI深度强化学习落地方法七步曲2——状态空间篇回报函数篇针对稀疏回报问题,学术界提出了很多方法,比如通过鼓励agent探索未见过的状态,提高正样本利用率,或者干脆用遗传算法或进化策略代替RL学习policy网络。这些方法不在本篇的讨论范围内,我们关心的是如何通过reward设计本身来规避稀疏回报问题,并尽可能提高训练效率和最终性能。 https://www.shangyexinzhi.com/article/4228946.html
16.《算法设计与分析基础(C++版)学习和实验指导》(李春葆陈良臣当当网图书频道在线销售正版《算法设计与分析基础(C++版)学习和实验指导》,作者:李春葆、陈良臣、喻丹丹,出版社:清华大学出版社。最新《算法设计与分析基础(C++版)学习和实验指导》简介、书评、试读、价格、图片等相关信息,尽在DangDang.com,网购《算法设计与分析http://product.dangdang.com/29583939.html