
算法初入
文章平均质量分 78
筱羊冰冰
这个作者很懒,什么都没留下…
展开
-
最大子数组的线性时间求解问题
之前有一个博客说的是使用分治的方式处理问题,但是我们可以看到实际上是将问题复杂化了。链接:最大子数组问题动态规划dp说白了就是一个个的不断尝试,来找到问题的最优解,那么动态规划就应该有一个状态转移方程,我们来看看这道题用动态规划能不能解决?算法导论还是很良心的,至少给了我们以下的思路:使用如下思想为最大子数组问题设计一个非递归的、线性时间的算法。从数组的左边界开始,从左至右处理,记录到目前为止已经处理过的最大子数组。若已知A[1…j]的最大子数组,基于如下性质将解扩展为A[1…j+1]的最大子数原创 2021-01-04 17:32:18 · 318 阅读 · 0 评论 -
匹配问题——匈牙利算法
先给出一些图论的定义(这部分其实也可以不看,第二个大标题开始讲正文)匹配给出图G = (V,E),我们取E的一个子集M,其中M中任意两条边没有公共顶点,我们则称M中的边为匹配边,同时将M中的点叫做匹配点。(剩下的叫未匹配边、未匹配点)极大匹配在一个匹配的基础上,我们可以扩大匹配(这个就是匈牙利算法的精髓,一会讲),当扩大到最大,我们就说这是一个极大匹配。最大匹配在极大匹配中,有的匹配边数会比其他的多一点,所以我们把最大的叫做最大匹配。完美匹配这个就更牛皮了,M连接的所有顶点刚好为V。二原创 2020-12-28 22:25:40 · 1748 阅读 · 0 评论 -
网络流问题
前言讲的是在一个有向图形成的网络中,我们需要找到其中的最大流量。这个问题是实际上也是有很大用处的。我们先描述一下问题:输入一个有向加权图(权值为这条边的最大容量),这个图有起点和终点,起点只有出度,终点只有入度,我们需要计算出从起点到终点的最大流量。举例:在这个问题中,我们的最大流量为30。解决办法先尝试找一条路径吧:就按照上面的例子,这里我们使用深度优先的树搜索方式,找到的路径为s->u->v->t。(这里面不需要看权值,只是随便找一个。如果不知道树搜索的原理,这里原创 2020-12-28 21:33:01 · 415 阅读 · 0 评论 -
图论——最短路径问题(bellman-ford、dijkstra、Floyd)
前言在一张图中,我们需要寻找到两个点之间的最短路径,这个问题在实际中也是很常用的。最短路径问题分为单源最短路径和任意两点之间的最短路径问题。单源最短路径输入一个有向加权图,我们要返回这个顶点到剩余顶点的最小距离。注意权值非负,如果有负圈,那么一些最短路径将会不存在。(一直在那里绕,路径为无穷小)优化子结构没错,这个问题涉及到了dp和贪心的解法,我们接下来进行讲解。最短路径的子路径也一定是最短。这个我们就可以通过反证法来证明,如果最短路径的子路经不是最短,那么我们直接替换就能将当前的最短路径原创 2020-12-28 21:01:11 · 1674 阅读 · 0 评论 -
字符串匹配问题(前缀表实现kmp、bmh、指纹思想)
前言之前写过一次kmp,当时采取的是比较常见的通过匹配来计算next数组,当时的那个确实很麻烦,这次我们给出一个更好的算法。之前的next数组求法是这样的:(给一下连链接)然后我们将带来新的字符串匹配算法,并且给出几种简单的算法求next数组的新方法先复习一下kmp算法:正常的匹配是如果匹配失败就将子串和主串都进行回退,然后重新开始匹配,但我们并不认为我们一定需要回退到子串的开始处,所以我们给出了next数组,来减少回退的程度。输入主串T(长n),和子串P(长m),寻找子串和主串匹配成功的起原创 2020-12-28 20:17:08 · 769 阅读 · 0 评论 -
树的搜索问题2——分支界限和A*算法(多阶段图问题、人员安排问题和旅行商问题)
前言在上一篇博客中我们简单提了一下深度优先和广度优先,然后就开始了爬山法和best-first算法。尽管貌似我们已经说了很多了,但是我们上一篇博客都是在围绕一个问题——所有的问题都是有一个确定的解,我们是在找解出问题的路径。但如果是一个优化解问题呢?比如在一个多阶段图中寻找从起点到终点的最短路径?这些算法其实是不能使用的,但这一类问题却很多,我们需要给出新的算法。(之前的算法也不是没有用,和深度优先广度优先差不多,也都是在给我们即将到来的算法做铺垫)分支界限法分支界限法又叫剪枝法顾名思义,其原创 2020-12-27 21:33:29 · 4957 阅读 · 7 评论 -
树的搜索问题1(深度优先、广度优先,爬山法和best-first)
前言我们在解决问题中经常使用到的数据结构一定少不了树,在数据结构这一大块中,我们对每一个结构都会讲各种形形色色的操作,比如栈的压栈出栈,树的各种遍历,但其实数据结构最重要的操作其实是搜索。如果我们不知道链表的搜索,如何插入删除?不知道图的搜索,如何寻找最小生成树?虽然我们讲的是树的搜索,但是本篇文章探讨的问题并非是树,而是将问题转化为树结构来处理。树的几种常见搜索方式我们先给出几种常用的例子吧。布尔表达式,给一组布尔变量和一个用这些变量组成的布尔表达式,需要寻找一种赋值方式使表达式为真8原创 2020-12-27 19:37:33 · 5693 阅读 · 3 评论 -
平摊分析的三种方法(聚集、会计和势能)+举例(栈操作、二进制加法器、动态表)
平摊分析(摊还分析)我们有时候会有一个算法,或者只是单纯的一系列操作,当我们需要将这一些操作计算一个平均代价,但是又不涉及概率的问题,我们就可以使用平摊分析。就比如一个月的账单,可能每一天都是正常的一日三餐,但是有一个周末出去玩花的钱可能会很多,如果你想计算一下这一个月平均每一天消费的上界,最简单的方式就是找最大消费的那天(出去玩),但是很明显这样是不合理的,但我们又没有概率支撑,不知道有多大的概率出去玩。这时就需要用到平摊分析了。三种方法聚集法看名字就知道了,这个方法也是很简单粗暴的,就是将所原创 2020-12-27 11:59:06 · 5336 阅读 · 1 评论 -
贪心算法的基本思想+任务安排问题、哈夫曼树、最小生成树算法(prim、kruskal)
什么是贪心算法顾名思义,贪心算法是通过判断当前状态下看起来最好的结果,作为最好的结果。一般来说,我们使用贪心算法的情况为需要一步步解决的问题,其中的每一个步骤都有一系列的选择,比如01背包问题,我们有C容量的背包,上来就选择能装下的最大价值物品,然后对剩下容量继续上述操作。(当然,如果知道的话,这种做法是错误的,我们将在后序给出讲解)所以问题就来了,我们通过贪心算法一定能得到最优解吗?还真不一定,我们需要进行证明,证明的关键点是优化子结构和贪心选择性。优化子结构在dp问题中也是谈了很多次了,也原创 2020-12-26 21:38:47 · 1855 阅读 · 0 评论 -
dp——动态规划练习2(二叉搜索树的构建+一些小例子和之前的优化)
二叉搜索树定义二叉搜索树,就是二叉查找树、二叉排序树,说白了就是一个思想:用一棵树存储一些元素值,其中我们保证左子树结点均小于根节点,右子树结点均大于根节点。直接从之前的博客中嫖了一张图:这颗树有很多很好的性质:首先中序遍历的结果是从小到大递增的,可以用于排序在查找的过程中,我们只需要从根节点出发,和跟结点对比即可,如果树的构建比较好,那么我们就可以保证O(logn)的查找效率这棵树还有一种形式,将每一个单分支结点和叶子节点都补上结点,构成一种新的树。我们可以看出,新补充的结点都是叶原创 2020-12-26 16:36:40 · 333 阅读 · 0 评论 -
dp——动态规划练习1(最长公共子序列问题、01背包问题)
最长公共子序列问题简介首先给出公共子序列的定义,即两个字符串中相同的子串,比如ababa和babd中的公共子序列有b、ba、ab、bab;而ababa和babca中,公共子序列为baba。(即中间可以相隔)所以我们可以这样总结,将两个字符串进行一定的删减,但不能改变元素顺序,最终得到的两个相同的子串,那么这个字串就是两个串的公共子序列。这个问题中我们需要寻找最大的子序列。分析要使用dp就一定要先证明可以使用,关于证明的部分在这里。我们需要证明存在重叠子问题和优化子结构。首先,我们可以看出这个问原创 2020-12-26 11:01:11 · 367 阅读 · 0 评论 -
dp——动态规划(+矩阵链乘法的例子)
前言这次我们开始讲述动态规划的具体思想,并给出一些具体的案例进行分析,比如为什么要使用dp我们都见过斐波那契数列这个例子,也都知道这个问题有一个递归的算法,但是有没有真正的分析过这个例子?我们来计算一个F(8),首先我们需要给出F(7)和F(6),调用递归函数来求解这两个数;求F(7)的过程中,我们需要F(6)和F(2),但是求F(5)的函数调用还没开始(或者是已经结束,变量出栈),导致计算机只能重新进行计算F(5);算F(5)同理,我们也是需要重复计算一些数值。当我们用树画出来,就长成了这原创 2020-12-25 11:52:23 · 846 阅读 · 2 评论 -
算法增长的阶的问题
引言——增长的阶在算法问题中,我们难免会被问到一个问题,这个算法究竟好不好?首先,尽管时代在发展,计算机的运算速度和内存在不断增大,但是我们面对的数据量也在不断增加,盲目使用不好的算法有时也能解决问题,但绝不是一个合适的方法。所以我们就有了算法时间空间复杂度分析的问题。一个算法耗时多少,很简单么,就把每一步加起来,如果是循环就相乘,问题不就解决了?但是在解决求和的过程中,我们还是会遇到很多问题的,而且一个级数放在那给别人看着也不方便,所以我们选择了一种表示方式。时间复杂度的表示方法因为我们只是一原创 2020-12-17 14:33:48 · 1013 阅读 · 0 评论 -
递归方程的求解(代入、递归树和主方法)
递归方程递归方程之前提到过,就是部分算法在求解的过程中使用了将一个问题划分成几个等价的小问题,在这个过程中,我们就可以列出一个等式。(如归并排序中,将一个大数组拆分成两个小数组分别计算,然后用O(n)的代价合并,T(n) = T(n/2)+O(n)就是一个递归方程)那么,在得到一个递归方程之后,我们应该如何求解问题呢?替换法/代入法我们都知道,归并排序的时间复杂度为O(nlogn),那么我们以后看到和上面给出的归并排序差不多的递归方程时,我们可能心中就有了一些猜想。没错,这个方式就是通过经验经原创 2020-12-17 14:32:31 · 17601 阅读 · 0 评论 -
分治算法举例——最大&最小值问题、大数乘法和棋盘规划
在之前的博客中给出了递归方程的含义,以及时间复杂度的计算方式,那么接下来给出一些典型的分治算法。寻找最大值和最小值问题给一个算法,寻找一个数组的最小值和最大值。(啥?这东西不是有手就行吗)emm,我这个不一样啊,我这个是O(1.5n)的时间复杂度的。方法一还记得快排里面的将一个数组划分成两个数组,保证大的在后小的在前吧,我们就是采用这样的方式,不过没有那么复杂。O(0.5n):将数组折半,最后一个和第一个比较、倒数第二个和第二个比较……将小的放在前半段,大的在后半段。O(n):遍历两个小数组原创 2020-12-17 14:31:36 · 534 阅读 · 0 评论 -
排序算法——堆排序
堆堆,是一种类似于二叉树的结构,或者说就是二叉树的一种。堆的每一个结点都有一个数值,并且有这样的性质:根节点比要比两个孩子节点都要大(至少也是相等),这样的堆叫做大顶堆,同样也有小顶堆的概念。排序首先声明,我们不需要创造一个二叉树来存储函数传递过来的数组信息,因为数组本身就可以构成一个二叉树,而且是完全二叉树。之前的关于数组存储二叉树的文章然后,我们需要整理这个数组使其成为一个大顶堆。(这里是以大顶堆为例,小顶堆同理)如何用数组实现大顶堆遍历二叉树的每一个结点,对于非叶子节点,将左孩子、右孩子原创 2020-10-08 22:23:19 · 254 阅读 · 0 评论 -
分治思想简介&最大子数组算法
定义将原来的问题划分成相同性质、规模更小的一些个子问题。如:归并排序,将一个数组拆分成两个、四个、直到最后只剩一个元素,然后反过来合并。递归方程分治问题最重要的就是递归方程,能看出来基本划分方式以及时间复杂度。如归并排序的递归方程为T(n)=2T(n/2)+O(n)其中T(n)是原问题的时间,T(n/2)是一半问题的时间,所以要乘2,O(n)是归并两个子序列需要的时间,为O(n),那么如果采用的是快排,那么这里就应该是O(1)了。快排中有和归并排序的比较,分析了为什么同样是nlong但是快排更原创 2020-10-02 16:55:06 · 471 阅读 · 0 评论 -
线性时间排序——基数排序、桶排序
之前一直以为基数排序就是桶排序,但是看了书发现还是有不同的。基数排序主要思想是按照位数划分,在每一位中按照计数排序的思想来进行。主要是应用于卡片排序机上(具体是啥不清楚了,但是貌似也是和计算有关的)例:321 986 123 432 543 018 765 678 987 789 098 890 109 901 210 0121.只看个位数,因为只有0-9这几种可能,每一种都给一个数组来存储:Q[0]:890 210Q[1]:321原创 2020-09-20 10:27:34 · 151 阅读 · 0 评论 -
线性阶时间排序——计数排序
新的排序方法?之前在讲快排中提到了,在比较排序中时间复杂度最小也就是o(nlogn)了,那么人们就想到了能不能基于其他的原理找到时间复杂度更低的方法?所以计数排序和基数排序就出现了。这次先讲计数排序先行思想给你10个不一样的数字,要你排序,如果知道每一个数有多少比他小的,那么直接放在数组里面合适的位置不就行了?那如果有相同的数字呢?我们可以考虑找一个数组,下标从0到数字中能出现的最大值,将每一个数字存储起来,最后再看下标放回去不就行了?例:1135542下面两行的数组中我们可以读出来有两原创 2020-09-20 09:28:58 · 252 阅读 · 0 评论 -
快速排序——思想和分析
思想本质上和归并差不多,都是以分而治之的方式来解决问题,将一个大问题划分成相同类型的几个小问题,然后不断递归下去达到问题的最小(每一组只有一个数据)最后将每一个小的排序合在一起,整个数据就是有序的了。那同样是分治的归并排序,为什么快排就敢叫这个名?(快排应该就是目前排序最快的了)快排的一个优点就是在合并的时候,不需要再次进行归并,(归并排序中到了合并的环节需要o(n)来将得到的两个子序列合并为有序),而且是原址修改即可。(归并还要单独的数组)交换之前提过了可以在原址上进行排序,不需要合并,那么说明原创 2020-09-19 10:21:33 · 256 阅读 · 0 评论