Q:一个一维向量:arr[n] = {i1,i2,i3,......,in} ,计算其连续子向量中最大和。(即截取连续的一段使得段中各元素和最大,元素有负值;子向量可以为空,即和最小为0)
A:
最初的想法是穷举,双层循环将所有连续的元素和算出来
for [i,n){ for[j,n){ caculate sum(arr[j],arr[j]); } }
这种方式虽然有效,但显得很蠢。
这里假设截取的区间是 arr[start, end] ,那么arr[start, end+1]的连续子向量的最大和能不能由arr[start, end]确定?
如果 arr[start, end] 符合条件的子向量(假设其最大和为maxsofar)含最后一个元素,那么arr[start, end+1]只需要看(end+1)这个位置,
如果 arr[start ,end] 符合条件的子向量不含最后一个元素,
那么arr[start, end+1]中符合条件的子向量要么是arr[start ,end]中的那个,要么是包含(end+1)这个元素的新的子向量(其最大和即arr[start,end]中含最后一个元素的最大和maxending+arr[end+1]);
所以对arr[n]有如下代码:
#define N 20 #define MAX(a,b) (a)>(b)?(a):(b) static int maxsofar=0; //表示arr[start, end]中连续子向量的最大和 static int maxending=0; //表示arr[start, end]中含(end)元素的最大和 /*static int start = -1;*/ //start的位置暂时没找到好的确定方法 static int end = -1; void findmax(){ int i=0; for( ; i<N; ++i){ maxending = MAX( maxending+arr[i], 0); //如果arr[start,end]中的maxending加上arr[end+1]小于0,则说明arr[start,end+1]中maxending为0; maxsofar = MAX(maxending,maxsofar); //arr[start,end+1]中的maxsofar为arr[start,end]中maxsofar 和 arr[start,end+1]中maxending的最大值; if(maxsofar==maxending) end = i; } } /*当arr[N] = {-39,45,26,-18,-92,17,-4,68,72,-2,99,4,-67,142,55,-59,19,-41,-72,13};时,输出为 maxsofar=384,end=14;*/
上述实现为线性级,效率比穷举的 n2 级要高很多。
时间: 2024-11-04 02:00:15