在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
问题描述: 给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。 输入格式: 输入第1行给出正整数 K (<= 100000);第2行给出K个整数,其间以空格分隔。 输出格式: 在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。 输入样例:6 -2 11 -4 13 -5 -2输出样例: 20 #include "stdafx.h" } int MaxSubsequenceSum(int a[],int N) 算法一:
int MaxSubsequenceSum(int a[],int N) int l =0; if(l == N) } 第二个循环大小为N-i,他可能要小,但也可能是N。我们必须假设最坏的情况,而这可能会使得最终的界有些大。第三个循环的大小为j-i+1,我们也要假设它的大小为N。为此总数为O(1*N*N*N)=O(N³)。语句1总的开销只是O(1),而语句7和8总共开销也只不过O(N²),因为他们只是两层循环内部的简单表达式。 我们在将结合各个语句的开销大小,更精确的分析出答案是θ(N³),而上面的估计高出个因子6(不过这并不影响,因为常数不影响数量级)。下面是具体计算的过程:
最后答案是(N³+3*N²+2*N)/6 显然这个算法过于消耗时间在第5行和第6行上的计算过分的耗时了。现在有一种改进的算法2 我们可以通过撤除一个for循环来避免立方运行时间。 下面是这个算法的函数: 算法2: int MaxSubsequenceSum(int a[],int N) int l = 0; for (i=0;i<10;i++) if(l == N)
这个算法显然是O(N²)的还有一种更简单的算法其相对时间复杂度为O(NlogN)解法,现在我们来描述它。 这个算法可以体现递归算法的优势,该方法采用一种“分治”策略。其想法是吧问题分成两个大致相等的子问题,然后递归地对它们求解,这是分部分。“治”阶段将两个子问题的解合并到一起并可能再做些少量的附加工作,最后得到整个问题的解。 在这个问题中,最大子序列和可能出现在3个地方。或者整个出现在输入数据的左半部分,或者整个出现在右半部分。或者跨越输入数据的中部从而占据左右两半部分。前两种情况可以递归求解。第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后将这两个和加在一起。 算法3: MaxLeftBorderSum=0;LeftBorderSum=0; } int MaxSubsequenceSum(const int a[],int N) 递归过程调用的一般形式是传递输入的数组以及左边界和右边界,它们界定额数组要被处理的部分。单行驱动程序通过传递数组以及边界0和N-1而启动该过程。 第一行至第四行处理基准情况。如果Left==Right,那么只有一个元素,并且当该元素非负时它就是最大和子序列。Left>Right的情况是不可能出现的,除非N是负数(不过程序中的小扰动有可能致使这种混乱产生)。第六行和第七行执行的两次递归调用。我们可以看到,递归调用总是对于小于原问题的问题进行,但程序总的小扰动有可能破换这个特性。第八行至第十二行以及第十三行至第十七行计算达到中间分界处的两个最大和的和数。这两个最大和的和为扩展到左右两边的最大和。伪例程Max3返回这三个有可能的最大和中的最大者。 显然,编程时,算法3比前面两种算法需要更多的精力。然而,程序短并不意味着程序号。正如我们在前面显示算法运行时间的表中已看到,除最小输入外,该算法比前面两个算法明显要快。 最后一种算法是最为有效的算法, 算法4: int MaxSubsequenceSum(int a[],int N) int l = 0; for(j=0;j<N;j++) if(l == N)
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论