求数组的子数组之和的最大值--编程之美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;
}
posted on 2011-04-05 15:19  tzc_yujunyong  阅读(355)  评论(0)    收藏  举报