求数组的子数组之和的最大值--编程之美2.14(待完善)
例题:Max Sequence
《编程之美》中的解法三:
nStart表示从a[i]到数组末尾中包含a[i]的和最大的一段数组元素之和。
nAll表示从a[i]到数组末尾中和最大的一段数组元素之和。
代码1:
View Code
int max(int a, int b)
{
return a>b ? a : b;
}
int MaxSum(int *a, int n)
{
int nStart=a[n-1];
int nAll=a[n-1];
for (int i=n-2; i>=0; i--)
{
nStart=max(a[i], nStart+a[i]);
nAll=max(nStart, nAll);
}
return nAll;
}
代码2(代码1的另一种写法):
View Code
int MaxSum(int* a, int n)
{
int nStart=a[n-1];
int nAll=a[n-1];
for (int i=n-2; i>=0; i--)
{
if (nStart<0) nStart=0;
nStart+=a[i];
//把(nStart+a[i], a[i])中大的赋值给nStart;
if (nStart>nAll) nAll=nStart; //把(nStart,nAll)中较大的赋值给nAll;
}
return nAll;
}
扩展问题:
1:如果数组(A[0],A[1],A[2],......,A[n-1])首尾相邻,也就是我们允许找到一段数字(A[i],A[i+1],......A[n-1],A[0],A[1],....,A[j]),使其和最大,怎么办?
解:问题分为两种情况,然后取二者中的最大值。
其1:解没有跨过....A[n-1],A[0].....(原问题),得到Max1。
其2:解跨过....A[n-1],A[0].....并且必定含有A[n-1],和A[0]。否则还是原问题。得到Max2。
对于这种情况,可以这样进行解答,一方面求以A[n-1]结尾的最大的一段和。另一方面求以A[0]开始的最大的一段和。(额,这是错的,书上这样解,因为这样的话,只要S(A[0]+.....+A[n-1])>0那么就会都加到头了。以A[n-1]结尾的最大的一段和与求以A[0]开始的最大的一段和其中很可能有重复的元素,即二者是相关的,有牵制的。不是无关的。)
即Max2=A[i]+A[i+1]+....+A[n-1]+A[0]+.....+A[j-1]+A[j].
这里关键是第二种情况怎么进行计算,书本上是错的。举例2,-2,3,5,-3,2 答案应该为10.即2+2+-2+3+5=10。
2:子序列之和的最大值,并且返回子序列的位置
下面的代码,如果存在多个最大的子序列,则只返回最前面的。
View Code
int begin = 0; //表示子数组之和最大数组的起始下标
int end = 0; //表示子数组之和最大数组的末尾下标
int MaxSum(int* a, int n){
int nStart = a[0];
int nAll = a[0];
int tmpStart = 0; //表示子数组之和最大数组临时的起始下标
for( int i = 1; i < n; i++)
{
if (nStart < 0)
{
nStart = 0 ;
tmpStart = i;
}
nStart += a[i];
if (nStart > nAll)
{
end = i;
nAll = nStart;
begin = tmpStart;
}
}
return nAll;
}

浙公网安备 33010602011771号