最大子序列和问题
来源:互联网 发布:企业站如何优化 编辑:程序博客网 时间:2024/06/11 19:35
给定(可能有负的)整数
例如:对于输入-2,11,-4,13,-5,-2,答案为20(从
我们将讨论求解该问题的四种算法,在某台计算机上的运行时间如下表所示。
从表中可以看出,对于小量的输入,这些算法都能在非常快的时间内完成,因此如果输入量很小,就没有必要设计聪明的算法了。对于大量的输入,显然算法4是最好的选择(当然算法3也是可用的)。
其次,表中所给出的时间不包括读入数据所需要的时间。对于算法4,仅仅从磁盘读入数据所用的时间很可能在数量级上比求解上述问题所需要的时间还要大,这也是许多有效算法的特点。
算法1:
算法1如以下代码所示,只是穷举式地尝试所有的可能,本算法不计算实际的子序列。
// Cubic maxium contiguous subsequence sum algorithmpublic static int maxSubSum1(int[] a){ int maxSum = 0; for(int i=0;i<a.length;i++) for(int j=i;j<a.length;j++){ int thisSum = 0; for(int k=i;k<=j;k++) thisSum += a[k]; if(thisSum > maxSum) maxSum = thisSum; } return maxSum;}
该算法运行时间为
我们可以通过撤除一个for
循环来避免三次的运行时间。纠正这种低效率的改进算法可以通过观察
算法2:
算法2显然是
// Quadratic maxium contiguous subsequence sum algorithmpublic static int maxSubSum2(int[] a){ int maxSum = 0; for(int i=0;i<a.length;i++){ int thisSum = 0; for(int j=i;j<a.length;j++){ thisSum += a[j]; if(thisSum > maxSum) maxSum = thisSum; } } return maxSum;}
算法3
对这个问题有一个递归和相对复杂的
在我们的例子中,最大子序列和可能在三处出现,或者整个出现在输入数据的左半部,或者整个出现在输入数据的右半部,或者跨越输入数据的中部从而位于左右两半部分之中。前两种情况可以递归求解,第三中情况的最大和可以通过求出前半部分(包含前半部分最后一个元素)的最大和以及后半部分(包含后半部分第一个元素)的最大和而得到,此时将两个和相加。
// Recursive maxium contiguous subsequence sum algorithm.// Finds maxium sum in subarray spanning a[left..right].// Does not attempt to maintain actual best sequence.private static int maxSumRec(int[] a, int left, int right){ if(left == right) // Base case if(a[left] > 0) return a[left]; else return 0; int center = (left+right)/2; int maxLeftSum = maxSumRec(a, left, center); int maxRightSum = maxSumRec(a, center+1, right); int maxLeftBorderSum = 0; int leftBorderSum = 0; for(int i=center;i>=left;i--){ leftBorderSum += a[i]; if(leftBorderSum > maxleftBorderSum) maxLeftBorderSum = leftBorderSum; } int maxRightBorderSum = 0; int rightBorderSum = 0; for(int i=center+1;i<=right;i++){ rightBorderSum += a[i]; if(rightBorderSum > maxrightBorderSum) maxrightBorderSum = rightBorderSum; } return max3(maxLeftSum, maxRightSum, maxLeftBorderSum+maxRightBorderSum);}// Driver for divide-and-conquer maxium contiguous// subsequence sum algorithmpublic static int maxSunbSum3(int[] a){ return maxSumRec(a, 0, a.length-1);}
根据分析的递归性质可知,实际上只有N是2的幂时结果才是合理的,否则我们最终要得到大小不是偶数的子问题,方程就是无效的;当N不是2的幂时,我们多少需要更加复杂一些的分析,但是大
算法4
// Linear-time maxium contiguous subsequence sum algorithmpublic static int maxSubSum4(int[] a){ int maxSum = 0; int thisSum = 0; for(int j=0;j<a.length;j++){ thisSum += a[j]; if(thisSum > maxSum) maxSum = thisSum; else if(thisSum < 0) thisSum = 0; } return maxSum;}
根算法1和算法2一样,j代表当前序列的终点,而i代表当前序列的起点。如题中所说,我们不需要知道最佳子序列的索引位置,于是i的还有那个可以从程序上被优化,因此在设计算法的时候假设i是需要的,而且我们想要改进算法2。
如果a[i]
是负的,那么它不可能代表最优序列的起点,因为任何包含a[i]
的作为起点的自学了都可以通过用a[i+1]
作为起点而得到更大的子序列和。类似的,任何负的子序列都不可能是最有子序列的前缀。如果在内循环中检测到从a[i]
到a[j]
的子序列是负的,那么可以将推进i
,关键的结论是, 我们不仅能够把i
推进到i+1
,实际上还可以一直推进到j+1
。为了更清楚,令p
为i+1
和j
之间的任一下标。开始于下标p
的任意子序列都不大于在下标i
开始并包含从a[i]
到a[p-1]
的子序列对应的子序列,因为后面的这个子序列不是负的(j
是使得从下标i
开始其值成为负值的序列的第一个下标)。因此,把i
推进到j+1
是没有风险的:我们一个最优解也不会错过。
- 最大和子序列问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题~~
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 最大子序列和问题
- 十大机器学习算法之AdaBoost
- Everything about Java 8
- 图像缩放算法
- Using OpenMP - The Examples
- SwingUtilities的invokeLater和invokeAndWait
- 最大子序列和问题
- poj 2109
- JAVA中IO流的应用
- iOS10适配秘籍
- MySQL主从复制数据一致性校验和修复方法及自动化实现
- Linux下redis的安装
- node.js实现回调
- Create Normal map from grayscale map
- 图片下面出现空白4像素BUG的常用解决方法归纳