问题——
给定N个整数(有可能是负数)A1,A2,A3,A4...An,求最大子序列和。
(子序列必须是连续的);比方,对于输入,-2,11,-4,13,-5,-2。这个序列,
答案是20,即从A2到A4。
对于这个问题,你怎么想的呢?以下有四种解法,看看你的解法是不是当中之中的一个。
解法一、穷举
解题思路——
既然是求某一个连续的子序列的最大和,那么我们把全部的子序列的和都加一遍。然后用一个变量来存储最大的和值。当遍历一遍全部子序列,就可以得到最大的和。
因为这个子序列长度能够是1。也能够是N。因此须要三重循环。
详细程序——
private static int calOne(int[] list){
int maxSum = 0;
for (int i = 0; i < list.length; i++) {
for (int j = i; j < list.length; j++) {
int thisSum = 0;
for (int k = i; k < j; k++) {
thisSum += list[k];
}
if (thisSum > maxSum) {
maxSum = thisSum;
}
}
}
return maxSum;
}
測试——
为了測试其性能。构建大量数据比較耗费时间。所以这里我让它反复计算某一个数组1万次。
public static void main(String[] args) {
int[] test = {-2,11,-4,13,-5,-219,23,234,-190,280,-20,1340,123,-324,43,-35};
long time = System.currentTimeMillis();
for (int i = 0; i < 9999; i++) {
calOne(test);
}
System.out.println(calOne(test));
System.out.println("算法1所用时间:"+(System.currentTimeMillis()-time)+"毫秒");
}
结果是:
1790
算法1所用时间:22毫秒
明显,三重循环,其执行时间是O(N^3)。
解法二、改进的穷举
通过观察。我们发现。事实上第三重循环是不必要的,由于第二次循环已经计算了第三次循环的数值。因此能够撤销。
private static int calTwo(int[] list) {
int maxSum = 0;
for (int i = 0; i < list.length; i++) {
int thisSum = 0;
for (int j = i; j < list.length; j++) {
thisSum += list[j];
if (thisSum > maxSum) {
maxSum = thisSum;
}
}
}
return maxSum;
}
撤销后的时间复制度是O(N^2),我们来看执行时间。
1790
算法2所用时间:6毫秒
确实降低了不少时间,可是这还是非常差劲的穷举算法。须要改进。
解法三、联机算法
联机算法优缺点——
在随意时刻,算法对要操作的数据仅仅读入(扫描)一次,一旦被读入并处理。它就不须要在被记忆了。
而在此处理过程中算法能对它已经读入的数据马上给出对应子序列问题的正确答案。具有这样的特性的算法叫做联机算法(on-line algorithm)。
该算法仅须要常量空间并以线性时间执行。因此联机算法差点儿是完美的算法。
长处:占用空间少。所用时间少
缺点:不宜设计。正确性不易观察。同一时候附加保留信息较少
详细程序——
private static int calThree(int[] list) {
int maxSum = 0,thisSum = 0;;
for (int j = 0; j < list.length; j++) {
thisSum += list[j];
if (thisSum > maxSum) {
maxSum = thisSum;
}else if(thisSum <0){
thisSum = 0;
}
}
return maxSum;
}
能够看到,联机算法的时间复杂度是O(N),节省了非常多时间。
执行验证下。
相同地计算一组数据1万次,结果是——
1790
算法3所用时间:2毫秒
关于这个问题。另一种分治策略的算法。尽管不如联机算法。可是比起差劲的穷举,还是改进不少的。
以上是个人的读书笔记,书籍为《数据结构与算法描写叙述》。
欢迎探讨。
本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5101388.html,如需转载请自行联系原作者